我参加了这个编程面试问题,我不确定我的答案是否正确。我无法找到这个问题的正确答案。这是问题,
设H1和H2为n1和n2个元素的两个(二进制)max-heaps 分别。如果H1中的每个元素都大于中的每个元素 H2,设计一种算法,将这两个堆合并为一个(二进制) O(n2)时间内的最大堆(假设H1和H2都足够大) 持有n1 + n2个元素)
所以,我认为由于H1中的每个元素都大于H2中的每个元素,因此我们可以将合并的最大堆存储在H1中。因此,我们所要做的就是从H2获取第一个元素,在H2的数组中的第0位,然后将该元素插入H1,附加到H1数组的末尾,使其成为H1中的叶子。我们可以继续为H2中的每个元素做到这一点。我想,一旦我们开始将H2中的元素作为子元素添加到H2的元素中,那么我们将不得不开始检查该子元素是否小于父元素,如果不是,则我们交换它们。我假设因为添加一个元素而不调用heapify,并在必要时交换会给我们一个复杂的O(n2)。
那么,我的解决方案是否准确?如果没有任何帮助将不胜感激。 请告诉我,如果我的解决方案的任何部分不清楚,我可以澄清一下。
答案 0 :(得分:2)
一般情况下,只能将H2附加到H1上,因为正如评论中指出的那样,这样做会产生无效的堆。这种情况并不是特别罕见。
例如,想象两个最大堆:
h1 = [100]
h2 = [6,3,5,1,2,4]
h1 h2
100 6
3 5
1 2 4
如果你只是将h2追加到h1,你会得到:
100
6 3
5 1 2 4
这显然是无效的,因为4是3的孩子。
如果h1 = [100,98]
,可能会发生同样的事情:
100
99 6
3 5 1 2
4
你需要做的是将h2追加到h1,然后运行缩写的 build-heap ,重新排列h2中的项目以反映它们在堆中的新位置。您已经知道从h2添加的所有项目都小于h1中的最小项目,因此您不必触及h1中的任何项目。
这与标准 build-heap 之间的唯一区别是起始位置和结束位置。基本上,你从h2的中间开始,然后向后工作到h2的开头。
h1_length = h1.length
h2_length = h2.length
h1.array.append(h2.array) // copies items from h2 to h1
// rearrange h2 items
start = h1_length + (h2_length/2)
for (item = start; item > h1_length; --item)
{
i = item
// This assumes that the root of the heap is at 0.
// If the root is at 1, then the left child is at i*2
while (i*2+1 < h1.length)
{
// get the largest child of this item
leftChildIndex = i*2+1
rightChildIndex = leftChildIndex + 1
largestChildIndex = leftChildIndex
if (rightChildIndex < h1.length &&
h1.array[rightChildIndex] > h1.array[leftChildIndex)
{
largestChildIndex = rightChildIndex
}
// if the item is greater than or equal to its largest child,
// then the item is where it belongs.
if (h1.array[i] >= h1.array[largestChildIndex])
{
break;
}
// swap the item with its child, and check again
swap(h1.array[i], h1.array[largestChildIndex])
i = largestChildIndex
}
}
build-heap 算法被证明是O(n),其中n是您正在构建的堆中的项目数。由于您只使用h2.length
项,因此需要O(h2.length)时间。