在O(k)中找到数组中最小的k个元素


12

我在网上发现了一个有趣的问题。给定一个包含n个数字的数组(不包含有关它们的信息),我们应该在线性时间内对该数组进行预处理,以便在给定一个数字1 <= k时,可以返回O(k)时间中的k个最小元素。 <= n

我一直在和一些朋友讨论这个问题,但没人能找到解决方案。任何帮助,将不胜感激!

快速说明:-k个最小元素的顺序并不重要-数组中的元素是number,可能是整数,可能不是(所以没有基数排序)-在预处理阶段不知道数字k。预处理是O(n)时间。在O(k)时间上的函数(找到k个最小元素)。


4
如何使用最小堆?
SHIR

1
看一下k-skyband和top-k计算。论文cs.sfu.ca/~jpei/publications/subsky_tkde07.pdf对相关文献进行了很好的回顾。
安德拉斯·萨拉蒙

1
西尔-我研究了最小堆的想法。但是,为了打印最小堆中的k个最小数字是O(klogn)时间,而不是O(k)
Idan

4
@idannik:为什么您要花费时间才能找到最小堆中的k个最小元素?Ω(klogn)k
Kristoffer Arnsfelt Hansen 2013年

8
我不认为这是研究水平。看起来像是一项作业。你在哪里找到它?
卡夫

Answers:


24

在时间O n )中预处理值的数组:nO(n)

  • in
  • i>2
    • 计算时间O i A [ 1 .. i ]的中位数mA[1..i]O(i)
    • 分区[ 1 .. / 2 - 1 ] [ / 2 + 1 .. ] 在同一时间。A[1..i]A[1..i/21]mA[i/2+1..i]m
    • ii/2

总预计算时间内O(1+2+4+...+n)O(n)

在时间O k )中回答A中的最小元素的查询:kAO(k)

  • llog2k
  • 选择 th元素X[ 2 .2 + 1 ]在时间Ö 2 Ô ķ (k2l)xA[2l..2l+1]O(2l)O(k)
  • 分区通过X在同一时间A[2l..2l+1]x

包含 ķ最小的元素。A[1..k]k

参考文献:

  • 1999年,Dor和Zwick提出了一种算法,可在2.942 n + o n )个比较之内及时计算元素的中值,从而产生了一种算法,可以从少于6 个n的比较中的n个无序元素中选择第k个元素。n2.942n+o(n)kn6n

1
我想外环被认为是'针对i在 '。您的算法与Yuval Filmus的答案不同吗?{2lgn,,4,2,1}
Radu GRIGore

2
这是我的算法对任意的推广。它还阐明了(故意)我的回答中遗漏的一些实现细节。n
Yuval Filmus 2013年

3
@YuvalFilmus您是否希望通过评论暗示我的回答在道德上接近于您?这是我审阅问题时想到的解决方案。我看到您发布了类似的文章,但不清楚,所以我写了自己的文章(而不是对您的文章进行重大编辑)。最终重要的是系统上答案的质量,而不是真正由谁编写的:徽章和声誉只是激励,而不是目标本身。
杰里米

4
@Jeremy一点也不;只是两个解决方案是相同的(但是您的解决方案适用于任意),并且我并没有充实细节,以防实际上这是一个家庭作业问题。n
Yuval Filmus 2013年

2
哦:(那很抱歉。(尽管我仍然认为给出完整的答案要优先于作业怀疑)
杰里米

14

为简单起见,假设。使用线性时间选择算法来寻找在位置上的元件2 - 12 - 22 - 3... 1 ; 这需要线性时间。鉴于ķ,发现使得2 - 1ķ 2 ; 注意,2 2 ķ。筛选出等级最高为2 t的所有元素n=2m2m1,2m2,2m3,,1kt2t1k2t2t2k2t,现在使用线性时间选择算法在时间O 2 t= O k )中找到位置处的元素kO(2t)=O(k)

澄清:似乎预处理需要时间Θ(nlogn),如果您不小心的话,确实是这种情况。以下是在线性时间内进行预处理的方法:

while n > 0:
  find the (lower) median m of A[0..n-1]
  partition A in-place so that A[n/2-1] = m
  n = n/2

就地分区就像在quicksort中一样进行。运行时间在是线性的,因此是线性的。最后,数组A满足以下属性:对于每个kA [ 0 .. n / 2 k - 1 ]n / 2 k个最小元素组成。n+n/2+n/4++1<2nAkA[0..n/2k1]n/2k


1
自然。如果对数组排序,则可以在解决此问题,而无需进行预处理。也许您不知道可以在时间O n )中找到第k个最大元素的线性时间选择算法?O(1)kO(n)
Yuval Filmus 2013年

4
@Yuval Filmus:你是不是运行算法次,共计ñ 日志ñ步骤?还是您有某种交错的想法?lognnlogn
安德拉斯·萨拉蒙

3
@AndrásSalamon:如果您阅读Jeremy给出的答案(在我看来,这个答案几乎与此相同),您会发现首先处理整个数组,然后处理前半部分,依此类推。
Radu GRIGore

3
n+n/2+n/4++1<2n

5
顺便说一句,在我对先前问题的回答中,此算法作为子例程出现:cstheory.stackexchange.com/questions/17378/…–
David Eppstein


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.