0

I was asked this question in an interview once and I grew curious as to what the best answer is. I primarily got stuck with providing a solution that traces a 2-d array in a time that's better than O(n^2). Here's the question:

/*
Here's a helper class that can efficiently return the smallest
object it contains. Assume it magically knows how to sort your
objects correctly.
*/

@interface MinHeap : NSObject

@property (readonly) NSUInteger count;

// Adds an object
- (void)addObject:(id)object;

// Returns (but does not remove) the smallest object, or nil if empty
- (id)minObject;

// Removes and returns the smallest object, or nil if empty
- (id)popMinObject;

// Removes all objects
- (void)removeAllObjects;

// **Implement this method**
- (NSArray*)process:(NSArray*)incomingArray
@end

/*
Sample input:
[ 
  [ @2, @4, @6 ],
  [ @1, @5, @10 ],
  [ @3, @7, @8, @98, @99 ],
  [],
  [ @4, @4 ]
]

Expected output:
[ @1, @2, @3, @4, @4, @4, @5, @6, @7, @8, @10, @98, @99 ]
*/

Here's the answer I gave:

- (NSArray*)process:(NSArray*)incomingArray
{
    // n squared
    for (int i=0; i<incomingArray.count; i++)
    {
        NSArray* row = incomingArray[i];

        for (int j=0; j<row.count; j++)
            [self addObject:row[j]];
    }

    NSMutableArray* returnArray = [NSMutableArray new];

    // n
    for (int i=0; i<self.count; i++)
        [returnArray addObject:[self minObject]];

    return [NSArray arrayWithArray:returnArray];
}

Apparently (if I were to have given his expected solution) I would have taken advantage of the assumption that the individual arrays inside the 2-d array are already sorted. The above solution did not convince my interviewer.

So, how can I use the above class in an efficient-than-O(n^2) way to produce the expected output?

P.S: A) Note that the individual arrays inside the sample input are always sorted. B) The input can have duplicates and the output should take contain duplicates.

Ravi
  • 7,029
  • 6
  • 36
  • 48
  • 2
    What is your question? Are you asking how a minheap works? Are you asking how to use a minheap to do sorting? You should know that using a minheap will not result in an O(n) sorting algorithm. – Jim Mischel Feb 23 '14 at 03:31
  • @JimMischel Clarified by giving more context and added my original answer. – Ravi Feb 23 '14 at 05:28
  • Try as I might, I cannot figure out why you would ever want to use a heap (even a magically efficient heap) to sort `k` sorted arrays rather than simply merging them. Surely there's something I'm missing here. Also, what are you calling `n` in your `O(n^2)`? In the double loop with the comment `// n squared` you're clearly calling `addObject` n times. We don't know the complexity of `addObject` but it would have to be a pretty bad implementation to be `O(n)`. – beaker Feb 25 '14 at 18:15
  • And I am assuming you meant to use `popMinObject` rather than `minObject` in the loop that builds the output array. – beaker Feb 25 '14 at 18:18

2 Answers2

1

If you have a magic data structure that can return the smallest element in O(1) time, then just add all the elements to the heap and pop them off from smallest to largest.

Jason
  • 11,310
  • 13
  • 63
  • 115
  • I thought about sets but I needed to deal with duplicates. Also, I was somehow inclined to believe that I was not giving a more straightforward solution. – Ravi Feb 23 '14 at 05:32
  • You need to only show value of each number? I would still do the same: add to the heap, pop off the min value, and then only add it to the sorted collection if it's greater than the last value. – Jason Feb 23 '14 at 14:22
  • Looks like there's some confusion. The problem is not how I would sort the collection, the (expected) improvement (from the interviewer) lies in how I read a 2-D array in a way that's more efficient than O(n^2). How can I do that? Note that the arrays inside the 2-d array are already sorted. – Ravi Feb 24 '14 at 00:21
1

If you have an object that implements that MinHeap interface, then you can build an O(n log n) sort like this. Note that this is pseudo code.

// first, build the heap
heap = new MinHeap();
for each item in the source array
    heap.addObject(item);

// now, repeatedly remove the minimum item until there are no more items
while (heap.count > 0)
    outputArray.Add(heap.popMinObject);

Inserting an item onto a heap takes O(log n) time, where n is the number of items currently on the heap. Removing the minimum item from a heap takes O(log n) time. So this method of using a heap to sort an array takes time proportional to 2*(n log n).

See Heap (data structure) at Wikipedia for details. Or, if you want a more long-winded explanation, read my series of blog posts on priority queues and heaps. The code examples there are in C#, but the first two articles are code agnostic.

Jim Mischel
  • 122,159
  • 16
  • 161
  • 305
  • I'm not concerned about the overall performance of the MinHeap. My question is: During the first step, how can I read the (individually sorted) 2-D array in better than O(n^2) way? – Ravi Feb 24 '14 at 00:34