我试图想出一些东西来解决以下问题:
给定一个表示为数组的max-heap,返回第k个最大元素而不修改堆。我被要求在线性时间内完成,但被告知可以在日志时间内完成。
我想到了一个解决方案:
使用第二个最大堆并用k或k + 1值填充它(宽度优先遍历到原始值)然后弹出k个元素并获得所需的值。我想这应该是O(N + logN)= O(N)
是否有更好的解决方案,可能是在O(logN)时间?
答案 0 :(得分:7)
max-heap可以有很多种方式,更好的情况是完整的排序数组,而在其他极端情况下,堆可以有一个完全不对称的结构。
这里可以看到:
在第一种情况下,第k个lagest元素位于第k个位置,您可以使用堆的数组表示在O(1)中计算。 但是,通常,您需要检查(k,2k)元素,并对它们进行排序(或与另一个堆进行部分排序)。据我所知,它是O(K·log(k))
算法:
Input:
Integer kth <- 8
Heap heap <- {19,18,10,17,14,9,4,16,15,13,12}
BEGIN
Heap positionHeap <- Heap with comparation: ((n0,n1)->compare(heap[n1], heap[n0]))
Integer childPosition
Integer candidatePosition <- 0
Integer count <- 0
positionHeap.push(candidate)
WHILE (count < kth) DO
candidatePosition <- positionHeap.pop();
childPosition <- candidatePosition * 2 + 1
IF (childPosition < size(heap)) THEN
positionHeap.push(childPosition)
childPosition <- childPosition + 1
IF (childPosition < size(heap)) THEN
positionHeap.push(childPosition)
END-IF
END-IF
count <- count + 1
END-WHILE
print heap[candidate]
END-BEGIN
EDITED
我在Frederickson找到了“最小堆中的最佳选择算法”: ftp://paranoidbits.com/ebooks/An%20Optimal%20Algorithm%20for%20Selection%20in%20a%20Min-Heap.pdf
答案 1 :(得分:4)
不,没有O(log n)-time算法,通过简单的单元探测下限。假设k是2的幂(不失一般性)并且堆看起来像(min-heap incoming,因为它更容易标记,但没有真正的区别)
1
2 3
4 5 6 7
.............
permutation of [k, 2k).
在最坏的情况下,我们必须读取整个排列,因为堆没有强加的顺序关系,并且只要找不到k,它就可以在尚未检查的任何位置。这需要时间Omega(k),匹配templatetypedef发布的(复杂!)算法。
答案 2 :(得分:2)
据我所知,没有简单的算法来解决这个问题。我所知道的最好的算法是由弗雷德里克森引起的并不容易。您可以查看论文here, but it might be behind a paywall.它在时间O(k)中运行,并且声称这是最佳时间,因此我怀疑不存在对数时间解决方案。
如果我找到比这更好的算法,我一定会让你知道。
希望这有帮助!
答案 3 :(得分:1)
数组中的最大堆:element at i is larger than elements at 2*i+1 and 2*i+2
(i
从0开始)
您需要另一个最大堆(insert
,pop
,empty
),其元素对(value, index)
按value
排序。伪代码(没有边界检查):
input: k
1. insert (at(0), 0)
2. (v, i) <- pop and k <- k - 1
3. if k == 0 return v
4. insert (at(2*i+1), 2*i+1) and insert (at(2*+2), 2*+2)
5. goto 2
运行时评估