18 April 2012

Design a stack such that getMinimum() should be O(1)


Non-constant-space solution
Keep a "duplicate" stack of "minimum of all values lower in the stack". When you pop the main stack, pop the min stack too. When you push the main stack, push either the new element or the current min, whichever is lower. getMinimum() is then implemented as just minStack.peek().
So using your example, we'd have:
Real stack        Min stack

5  --> TOP        1
1                 1
4                 2
6                 2
2                 2
After popping twice you get:
Real stack        Min stack

4                 2
6                 2
2                 2
Please let me know if this isn't enough information. It's simple when you grok it, but it might take a bit of head-scratching at first :)
(The downside of course is that it doubles the space requirement. Execution time doesn't suffer significantly though - i.e. it's still the same complexity.)
EDIT: There's a variation which is slightly more fiddly, but has better space in general. We still have the min stack, but we only pop from it when the value we pop from the main stack is equal to the one on the min stack. We only push to the min stack when the value being pushed onto the main stack is less thanor equal to the current min value. This allows duplicate min values. getMinimum() is still just a peek operation. For example, taking the original version and pushing 1 again, we'd get:
Real stack        Min stack

1  --> TOP        1
5                 1
1                 2
4                 
6                 
2
Popping from the above pops from both stacks because 1 == 1, leaving:
Real stack        Min stack

5  --> TOP        1
1                 2
4                 
6                 
2
Popping again only pops from the main stack, because 5 > 1:
Real stack        Min stack

1                 1
4                 2
6                 
2
Popping again pops both stacks because 1 == 1:
Real stack        Min stack

4                 2
6                 
2
This ends up with the same worst case space complexity (double the original stack) but much better space usage if we rarely get a "new minimum or equal".
Here's a quick implementation
public sealed class MinStack {
    private int MinimumValue;
    private readonly Stack<int> Stack = new Stack<int>();

    public int GetMinimum() {
        if (IsEmpty) {
            throw new InvalidOperationException("Stack is empty");
        }
        return MinimumValue;
    }

    public int Pop() {
        var value = Stack.Pop();
        if (value == MinimumValue) {
            MinimumValue = Stack.Min();
        }
        return value;
    }

    public void Push(int value) {
        if (IsEmpty || value < MinimumValue) {
            MinimumValue = value;
        }
        Stack.Push(value);
    }

    private bool IsEmpty { get { return Stack.Count() == 0; } }
}



No comments:

Post a Comment