1

I came along this programming interview question and I am unsure if my answer is right. I was unable to find a proper answer to this question. Here is the question,

Let H1 and H2 be two (binary) max-heaps with n1 and n2 elements respectively. If every element in H1 is larger than every element in H2, design an algorithm that merges these two heaps into one (binary) max-heap in O(n2) time (assume that both H1 and H2 are large enough to hold n1 + n2 elements)

So, I was thinking that since every element in H1 is greater than every element in H2 then we can store the merged max heap in H1. So, all we have to do is simply get the first element from H2, at position 0 in the array for H2, and then insert that element into H1, append to the end of the array of H1 making it a leaf in H1. We can continuously do that for every element in H2. I suppose that once we start adding elements from H2 as children to elements of H2 then we will have to start checking whether that child is less than the parent and if not we swap them. I'm assuming that since adding an element, without calling heapify, and swapping when necessary will give us a complexity of O(n2).

So, is my solution accurate? If not any help will be much appreciated. Please tell me if any part of my solution is unclear so I can clarify.

gsamaras
  • 66,800
  • 33
  • 152
  • 256
name
  • 371
  • 2
  • 11
  • It feels like it is accurate. But i have created a case that you need to do more than one swap. Considering H1 is very small relative to H2; this means you will need almost log(n2) swaps for one element (H1:[100], H2[25 8 24 3 7 10 23 2 1 6 5 4 9 12 22]). Yet it is supposed to be encountered very rare. If we can proove that this situation will be encountered ignorably rare then you are right:) – seleciii44 Oct 22 '17 at 19:21
  • So will my complexity for my algorithm actually be O(n2 + log(n2))? I do not have too much experience with calculating complexity so I am not sure about that. Would that still just be O(n2)? – name Oct 22 '17 at 19:56
  • Honestly, I'm not sure for now :( – seleciii44 Oct 22 '17 at 20:09
  • @selecii44: The number of possible errors increases with the size of the heap you're merging (i.e., n2). Locating the nodes to swap would be an O(n2) operation, and fixing them would take O(log n2) for each. The solution is to rearrange the entire n2 heap in O(n2). That makes the entire operation O(2*n2), which is considered O(n2). – Jim Mischel Oct 24 '17 at 18:07

1 Answers1

2

You can't in general just append H2 onto H1, because as was pointed out in comments, doing so can produce an invalid heap. This situation is not especially rare.

For example, imagine two max heaps:

h1 = [100]
h2 = [6,3,5,1,2,4]

    h1        h2

   100        6
            3   5
           1 2 4

If you just append h2 to h1, you get:

    100
  6    3
 5 1  2 4

Which is clearly invalid, because 4 is a child of 3.

If h1=[100,98], the same kind of thing can happen:

       100
    99     6
   3  5  1   2
 4

What you have to do is append h2 to h1, and then run an abbreviated build-heap that rearranges the items from h2 to reflect their new positions in the heap. You know already that all the items you added from h2 are smaller than the smallest item in h1, so you don't have to touch any item from h1.

The only difference between this and the standard build-heap is the starting and ending positions. Basically, you start in the middle of h2, and work backwards to the beginning of 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
    }
}

The build-heap algorithm is proven to be O(n), where n is the number of items in the heap that you're building. Since you're only working with h2.length items, this will take O(h2.length) time.

Jim Mischel
  • 122,159
  • 16
  • 161
  • 305