【发布时间】: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 的第一个解决方案相同。您实际上可以随时计算子分区总和。
标签: algorithm duplicates top-n