重复大量输入的快速选择算法?
Posted
技术标签:
【中文标题】重复大量输入的快速选择算法?【英文标题】:Fast selection algorithm for duplicate-heavy inputs? 【发布时间】:2021-10-01 17:03:42 【问题描述】:我已经熟悉了快速选择和中位数的中位数,用于快速选择未排序数组中的第 k 个元素。如果你足够努力,你可以保证最坏情况的时间复杂度在 O(n)。
我的问题有点不同。我想从包含大量不可预测重复的未排序数组中选择第 k 个数字。我想知道的是,与输入n
的总大小相比,是否存在一种既能节省内存又能节省时间的方法来处理唯一值u
的数量。问题是有时u << n
有时u ~ n
。 (实际上,u
几乎是不变的,而n
波动很大。)
不好的方法1(请原谅我的python伪代码,问题与python没有具体关系):
input = ...
k = ...
m = hashmap()
for value in input:
if value exists in m:
m[value] = m[value] + 1
else:
m[value] = 1
cumulative_sum = 0
for unique_value in ordered(m):
cumulative_sum += m[unique_value]
if cumulative_sum > k:
return unique_value
这是我目前的基准。我不喜欢的是使用比较对m
进行排序或保持排序需要O(u*logu)
时间。
错误方法 2:
input = ...
k = ...
M = some_value
assert type(input) == integral
assert min(input) == 0
assert max(input) == M
a = array(size=M+1, default_value=0)
for value in input:
m[value] = m[value] + 1
cumulative_sum = 0
for i in range(M+1):
cumulative_sum += m[i]
if cumulative_sum > k:
return i
这显然很糟糕,因为它需要O(M)
时间和O(M)
空间。
有没有什么好的方法来更新快速选择(或完全做其他事情)来解决O(u)
时间和O(u)
空间中的问题?
正如@kcsquared 所说,如果输入数组按原样给出,则无法打破Omega(n)
时间限制。如果输入格式为[(v1, c1), (v2, c2), ..., (vn, cn)]
,是否会发生任何变化,其中(v, c)
对应一个唯一值; v
是值,c
是它在原始输入中出现的次数?
【问题讨论】:
您是否对同一个数组进行重复的选择查询?否则,您需要至少查看数组的每个元素一次(如果您事先不知道u
)所以Omega(n)
对于时间复杂度来说是不可避免的。
@kcsquared 不,只有一个选择查询。你当然是对的。假设您实际上确实提前知道 u
:如果您的新输入是 2 元组 (v, c)
,其中 v
将是您的值,c
将是它在原始输入中出现的数量。这会改变什么吗?
荷兰国旗分区算法在这里可能有些用处。 en.wikipedia.org/wiki/Dutch_national_flag_problem
@CiaPan 谢谢你的建议;可能是我遗漏了一些东西,但我认为该算法不能用于解决这个问题,因为该算法通过整个数组(j
和k
相遇),这使得它@ 987654349@,更不用说输入查询是一个值,而不是一个索引。
是的,基本上。这与@btilly 的第一个解决方案相同。您实际上可以随时计算子分区总和。
【参考方案1】:
为了记忆,是的。
创建一个哈希映射值来计数。此哈希的大小为O(u)
。然后您可以进行快速选择,为每个值赋予与计数相等的权重。
但是,您必须阅读整个数组,即O(n)
。除非您对大概的答案感到满意。在这种情况下,您可以从数组中随机选择,找出近似计数的哈希值,然后快速选择它。根据目的,这可能已经足够接近了。
【讨论】:
不幸的是,近似值是不够的(关键管道的一部分)。但是,谢谢您的回答,我想我刚刚知道更新后的快速选择是如何工作的。我明天会实施并尽快回复您!以上是关于重复大量输入的快速选择算法?的主要内容,如果未能解决你的问题,请参考以下文章