Start learning free

LESSON 397 OF 539 · STACK

Min Stack in C#: O(1) Minimum with Two Stacks

Practice O(1) Read the full explanation

A stack hands its values back in the opposite order they arrived: the last value pushed is the first one popped. Design a stack that can also say, at any moment, which value is the smallest of all the values it holds, and do every operation in constant time.

Implement the class MinStack:

  • MinStack() creates an empty stack.
  • push(val) puts the integer val on top of the stack.
  • pop() removes the value on top of the stack.
  • top() returns the value on top of the stack, without removing it.
  • getMin() returns the smallest value in the stack, without removing anything.

The input is a list of operations, applied in order to one new MinStack. The output lists what the top and getMin calls return, in order. The starter code spells these names the way your language does.

 

Example 1:

Input:
    push(-2)
    push(0)
    push(-3)
    getMin()
    pop()
    top()
    getMin()
Output: -3 0 -2
Explanation:
After the three pushes the stack holds -2, 0 and -3, with -3 on top, so the smallest value is -3.
pop() removes -3. Now 0 is on top, and the smallest value is -2 again: when the minimum leaves,
the minimum from before it arrived comes back.

Example 2:

Input:
    push(5)
    push(5)
    push(7)
    getMin()
    pop()
    pop()
    getMin()
    top()
Output: 5 5 5
Explanation: 5 is pushed twice. The two pops remove 7 and one of the 5s, but the other 5 is still in the stack, so the smallest value is still 5.

Example 3:

Input:
    push(3)
    top()
    getMin()
    push(1)
    push(2)
    top()
    getMin()
    pop()
    pop()
    getMin()
Output: 3 3 2 1 3
Explanation: The value on top (2) and the smallest value (1) can be different values. Once 2 and 1 are popped, only 3 is left, and it is the smallest again.

 

Constraints:

  • -231 <= val <= 231 - 1
  • pop, top and getMin are only called when the stack is not empty.
  • At most 2 * 105 calls in total are made to push, pop, top and getMin.

Note:

Each operation should run in O(1) time. Looking through the whole stack for its smallest value in getMin would take O(n) time per call, where n is the number of values in the stack.

STEP 1 OF 9
    Ctrl + Enter to check

    C# · STACK

    Min Stack in C#, explained

    Problem overview

    A stack gives values back in reverse order: the last value pushed is the first one popped. The MinStack class must behave like a stack and also answer one more question at any moment: what is the smallest value it holds right now? Every operation, Push, Pop, Top and GetMin, has to run in constant time. The tests only call Pop, Top and GetMin on a non-empty stack, and values can be any int.

    Take the first example. After pushing -2, 0 and -3, the stack holds those three values with -3 on top, so GetMin returns -3. After Pop removes -3, Top returns 0 and GetMin returns -2. The minimum that was current before -3 arrived comes back. Running the lesson's class on this sequence prints -3, 0, -2.

    Approach: remember the minimum next to every value

    The obvious GetMin loops over everything in the stack and costs O(n) per call. Keeping a single variable min looks cheaper, but it breaks as soon as the minimum is popped: you would have to scan the rest of the stack to find the new one.

    The way out is to notice that a value only leaves the stack after every value above it has left. So the values below it never change while it is in the stack, and the smallest value from the bottom up to that position can be computed once, when the value is pushed, and then kept. The class stores two stacks of equal height:

    • stack holds the values themselves.
    • minStack holds, at each depth, the smallest value from the bottom of the stack up to that depth.

    The top of minStack therefore describes the whole stack as it is now. Popping removes the top of both stacks, and the previous minimum is uncovered automatically. No search is needed.

    Duplicates need no special case. In the second example, 5 is pushed twice and then 7. The two stacks hold 5, 5, 7 and 5, 5, 5. After two pops, one 5 remains in both, and GetMin still returns 5. The last line of that run prints 5 for GetMin and 5 for Top.

    Step by step

    1. Declare stack as a field of type Stack<int> with an initializer, so the object starts with an empty stack and needs no constructor.
    2. Declare minStack the same way. Its entry at each depth is the minimum of the value at that depth and everything below.
    3. In Push, push val onto stack first. The ordinary stack stores the value unchanged.
    4. Start currentMin at val. If the stack was empty, val is the only value, so it is also the smallest.
    5. If minStack isn't empty, replace currentMin with the smaller of itself and the top of minStack. The top is already the minimum of everything below, so one comparison with Math.Min is enough.
    6. Push currentMin onto minStack. Now both stacks have the same height, and equal values are recorded each time they are pushed.
    7. In Pop, pop from both stacks, one line each. They must stay the same size, or the entries stop lining up.
    8. In Top, return stack.Peek(). Peek reads the top; only Pop removes it.
    9. In GetMin, return minStack.Peek(). The answer is already stored.

    The solution in C#

    class MinStack {
        Stack<int> stack = new Stack<int>();
        Stack<int> minStack = new Stack<int>();
    
        public void Push(int val) {
            stack.Push(val);
            int currentMin = val;
            if (minStack.Count > 0) {
                currentMin = Math.Min(currentMin, minStack.Peek());
            }
            minStack.Push(currentMin);
        }
    
        public void Pop() {
            stack.Pop();
            minStack.Pop();
        }
    
        public int Top() {
            return stack.Peek();
        }
    
        public int GetMin() {
            return minStack.Peek();
        }
    }
    

    The C# details worth knowing:

    • Stack<T> API. It lives in System.Collections.Generic. Push adds on top, Pop removes and returns the top, Peek returns the top without removing it, and Count is a property, not a method, so there are no parentheses.
    • Empty stacks throw. Pop or Peek on an empty Stack<int> throws an InvalidOperationException with the message "Stack empty." The tests never do this, which is why Pop can call both pops without checking. That is also why minStack.Count > 0 is checked before Peek in Push.
    • Pop returns a value. stack.Pop(); on its own line discards the returned value, which is fine here because the method returns nothing.
    • Fields default to private. The two stacks have no access modifier, so they are private to the class, which is what you want: callers must go through the four methods, or the stacks could drift out of step.
    • Extreme values. Comparing never overflows, unlike adding or subtracting. Pushing int.MinValue and then int.MaxValue gives a GetMin of -2147483648 and a Top of 2147483647.
    • Naming. C# methods use PascalCase (GetMin), so code ported from another language's getMin will not match the lesson's tests.

    Complexity

    Time: O(1) per operation. Push does two pushes, one comparison and one Peek. Pop does two pops. Top and GetMin do one Peek each. A .NET Stack<T> is backed by an array, so a push is constant time except on the occasional resize, which averages out to constant (amortized).

    Space: O(n). Two stacks, each with one entry per value currently held. The second stack doubles the memory, which is the price of the constant-time minimum.

    Edge cases and common mistakes

    • One variable for the minimum. It fails after the minimum is popped, because the previous minimum is lost. The second stack exists to keep it.
    • Pushing to minStack only when a new minimum arrives. That works only if equal values are handled too. With push(5), push(5), pop(), a stack that skipped the second 5 would pop the only 5 in minStack and then have nothing to answer with. Pushing currentMin every time avoids the issue.
    • Forgetting one of the two pops. The stacks fall out of step, and GetMin starts returning minimums that belong to other depths.
    • Pushing val instead of currentMin to minStack. GetMin then returns the top value, not the smallest.
    • Confusing Top and GetMin. After pushing 3, 1, 2, Top is 2 and GetMin is 1. After two pops, only 3 is left and it is both.
    • Calling the wrong method name. Push, Pop, Peek are capitalised in C#. push or peek will not compile.

    Testing

    • push(-2), push(0), push(-3), getMin, pop, top, getMin gives -3 0 -2.
    • push(5), push(5), push(7), getMin, pop, pop, getMin, top gives 5 5 5.
    • push(3), push(1), push(2), top, getMin, pop, pop, getMin gives 2 1 3.
    • push(int.MinValue), push(int.MaxValue), getMin, top gives -2147483648 2147483647.
    Keep going with C#500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free