Start learning free

LESSON 393 OF 535 · STACK

Min Stack in C++: O(1) getMin with a Second Vector

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 the opposite order they went in. The class MinStack has to behave like a stack, with push, pop and top, and it also has to answer getMin: the smallest value currently in the stack. Every operation must take constant time. The input is a list of operations applied to one new MinStack, and the output is what the top and getMin calls return. The stack is never empty when pop, top or getMin is called.

    Take the first example: push -2, push 0, push -3. The stack holds -2, 0, -3 with -3 on top, so getMin() gives -3. After pop() removes -3, top() gives 0 and getMin() gives -2. The output is -3 0 -2. The point of that example is that when the minimum leaves the stack, the minimum from before it arrived comes back.

    Approach: remember the minimum at every depth

    The obvious way to find the smallest value is to look at all of them, which costs O(n) per getMin call. With up to 200,000 operations that is too slow, and the statement asks for O(1).

    Keeping one variable with the current minimum is not enough: after the minimum is popped, the variable would have to be recomputed from what is left. The fix is to store more. A value can only leave the stack after every value above it has left, so the values below it do not change while it is in the stack. That means the minimum of "this value and everything below it" can be computed once, when the value is pushed, and written down next to it.

    The class therefore keeps two vectors of the same length. stack holds the values. minStack holds, at each depth, the smallest value from the bottom up to that depth. The last entry of minStack describes the whole stack as it is now, so getMin only reads it. Popping removes the last entry of both, and the previous entry of minStack is the minimum the stack had before that value arrived.

    After pushing -2, 0 and -3, the two vectors hold:

    stack:    -2  0 -3
    minStack: -2 -2 -3

    The 0 does not lower the minimum, so its entry repeats -2. After the pop, the last entry of minStack is -2 again.

    Step by step

    1. Declare stack as a vector<int> under public:. The end of a vector is the top of the stack, because push_back, back and pop_back all work at that end in constant time.
    2. Declare minStack as a second vector<int>. Its entry at each depth is the smallest of the value at that depth and everything under it.
    3. In push, add val to stack with push_back.
    4. Start currentMin at val. If the stack was empty, val is its only value and so its minimum.
    5. If minStack is not empty, lower currentMin with min(currentMin, minStack.back()). The last entry already is the smallest of everything below, so one comparison is enough.
    6. Push currentMin onto minStack. Both vectors now have the same size. Equal values are pushed too, so a minimum that was pushed twice is remembered twice.
    7. In pop, remove the last element of both vectors. They must stay the same size.
    8. top returns stack.back(), which reads the last element and removes nothing.
    9. getMin returns minStack.back(), the answer that was stored when the top value arrived.

    The solution in C++

    class MinStack {
    public:
        vector<int> stack;
        vector<int> minStack;
    
        void push(int val) {
            stack.push_back(val);
            int currentMin = val;
            if (!minStack.empty()) {
                currentMin = min(currentMin, minStack.back());
            }
            minStack.push_back(currentMin);
        }
    
        void pop() {
            stack.pop_back();
            minStack.pop_back();
        }
    
        int top() {
            return stack.back();
        }
    
        int getMin() {
            return minStack.back();
        }
    };
    

    The C++ details worth a closer look:

    • Vectors as stacks. A vector does everything a stack needs at its end, in amortized constant time. The standard library also has std::stack, but it has no begin or indexing, and a plain vector is simple enough here.
    • back() and pop_back() on an empty vector are undefined behaviour. The constraints promise that pop, top and getMin are only called on a non-empty stack, so the code does not check. push does check minStack.empty(), because it is the one call made on an empty stack.
    • pop_back() returns nothing. It removes the element but does not hand it back, which is why pop in this class returns void.
    • Full 32-bit range. Values go from -2147483648 to 2147483647, and int holds exactly that. The code only compares values and never adds or subtracts them, so no overflow can happen. With push(INT_MIN) then push(INT_MAX), getMin() returns -2147483648 and top() returns 2147483647.

    Complexity

    Time: O(1) per operation. Every method does a fixed number of vector operations at the end of a vector. push_back is amortized constant: now and then the vector reallocates and copies its elements, but that cost is spread over many pushes.

    Space: O(n). For n values in the stack, the two vectors hold 2n integers. That is the price of constant-time getMin.

    Edge cases and common mistakes

    • Duplicate minimums. Push 4, 2, 2, then pop once: getMin() returns 2, because the other 2 is still there. After a second pop it returns 4. A design that stores each distinct minimum only once breaks here. Storing a minimum per depth, as this one does, handles it for free.
    • One variable for the minimum. It is correct until the minimum is popped, and then there is no way to recover the previous one in constant time.
    • Different top and minimum. After pushing 3, 1, 2, top() is 2 and getMin() is 1. Returning one when the other is asked for is an easy slip when the two vectors are named alike.
    • Popping only one vector. If pop forgets minStack.pop_back(), the sizes drift apart and getMin keeps answering for values that have left.
    • Comparing with the wrong entry. The comparison uses minStack.back(), the minimum of everything below. Comparing with stack.back() would only look at the value just under the new one.

    Testing

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