重复输入的快速选择算法?
Fast selection algorithm for duplicate-heavy inputs?
我已经熟悉了 quickselect 和 median-of-medians 用于快速 selection 未排序数组中的第 k 个元素。如果你足够努力,你可以保证最坏情况下的时间复杂度在 O(n) 之内。
我的问题有点不同。我想 select 来自未排序数组的第 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)
space。
有没有什么好的方法可以快速更新select(或者干脆干点别的)在O(u)
时间和O(u)
space解决问题?
正如@kcsquared 指出的那样,如果输入数组按原样给出,则无法打破 Omega(n)
时间限制。如果输入的格式为 [(v1, c1), (v2, c2), ..., (vn, cn)]
,是否有任何变化,其中 (v, c)
对应于一个唯一值; v
是值,c
是它在原始输入中出现的次数?
为了记忆,是的。
创建哈希映射值以进行计数。此散列的大小为 O(u)
。然后你可以做一个快速选择,给每个值一个等于计数的权重。
但是为了时间,你必须读取整个数组 O(n)
。除非您对近似答案感到满意。在这种情况下,您可以从数组中随机选择,计算出近似计数的散列,然后快速选择它。根据目的,这可能足够接近了。
我已经熟悉了 quickselect 和 median-of-medians 用于快速 selection 未排序数组中的第 k 个元素。如果你足够努力,你可以保证最坏情况下的时间复杂度在 O(n) 之内。
我的问题有点不同。我想 select 来自未排序数组的第 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)
space。
有没有什么好的方法可以快速更新select(或者干脆干点别的)在O(u)
时间和O(u)
space解决问题?
正如@kcsquared 指出的那样,如果输入数组按原样给出,则无法打破 Omega(n)
时间限制。如果输入的格式为 [(v1, c1), (v2, c2), ..., (vn, cn)]
,是否有任何变化,其中 (v, c)
对应于一个唯一值; v
是值,c
是它在原始输入中出现的次数?
为了记忆,是的。
创建哈希映射值以进行计数。此散列的大小为 O(u)
。然后你可以做一个快速选择,给每个值一个等于计数的权重。
但是为了时间,你必须读取整个数组 O(n)
。除非您对近似答案感到满意。在这种情况下,您可以从数组中随机选择,计算出近似计数的散列,然后快速选择它。根据目的,这可能足够接近了。