Algorithm

Min Stack

Design Pattern

Min Stack

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. Implement the MinStack class: MinStack() initializes the stack object. void push(int val) pushes the element val onto the stack. void pop() removes the element on the top of the stack. int top() gets the top element of the stack. int getMin() retrieves the minimum element in the stack. You must implement a solution with O(1) time complexity for each function.

CONSTRAINTS
  • -2³¹ <= val <= 2³¹ - 1
  • pop, top and getMin are always called on a non-empty stack
  • At most 3 × 10⁴ calls will be made to push, pop, top, and getMin
EXAMPLE 1
Input: push(-2), push(0), push(-3), getMin(), pop(), top(), getMin()
Output: -3, 0, -2
Push -2 (min=-2), push 0 (min=-2), push -3 (min=-3). getMin()=-3. Pop -3. top()=0. getMin()=-2 (reverts to previous min).
EXAMPLE 2
Input: push(1), push(2), getMin(), pop(), getMin()
Output: 1, 1
Both getMin calls return 1 because 2 is never the minimum.
EXAMPLE 3
Input: push(0), push(1), push(0), getMin(), pop(), getMin()
Output: 0, 0
Duplicate minimum: push 0 twice. After popping one 0, getMin still returns 0 because the first 0 remains.

A stack is a pile you touch only from the top: push adds on top, pop removes the top, top peeks at it — all instant, O(1). The twist here is a fourth request, getMin, which must return the smallest value anywhere in the stack, also in O(1). That's the tension: a stack only ever exposes its top, but the minimum could be buried at the very bottom.

The honest attempt, and why it's too slow

Keep an ordinary stack and, when getMin is asked, scan all the stored values for the smallest. Correct, but scanning N elements is O(N) per call — and with up to 3 × 10⁴ calls that's quadratic overall. The waste is obvious once named: we recompute the minimum from scratch every single time, even though the stack barely changed since the last call. Whenever you catch yourself recomputing an answer that only shifts a little between calls, the fix is usually to remember it instead.

The insight: the minimum is tied to the stack's height

Here's the fact that unlocks O(1). A stack only changes at the top — you can't touch the middle. So consider the moment any value x is pushed: the minimum of everything at or below it is fixed forever, because nothing beneath x can change until x itself is popped. In other words, each depth of the stack has its own permanent minimum: the min of the whole stack when the stack was that tall. If we could store, next to each element, "the minimum of everything from here down," then getMin is just reading that number off the top.

The mechanism: a parallel min-stack

Keep a second stack, min_stack, that rises and falls in lockstep with the main one. Its top always holds the minimum of the current main stack. On push(x), the new overall minimum is simply x compared against the previous minimum (the current min_stack top) — push the smaller of the two. On pop, remove the top of both stacks together, so min_stack's top automatically falls back to the minimum that was true one level down. getMin reads min_stack's top. Everything is O(1).

python
class MinStack:
    def __init__(self):
        self.stack = []
        self.min_stack = []      # min_stack[i] = min of stack[0..i]

    def push(self, val):
        self.stack.append(val)
        cur_min = val if not self.min_stack else min(val, self.min_stack[-1])
        self.min_stack.append(cur_min)

    def pop(self):
        self.stack.pop()
        self.min_stack.pop()     # keep the two perfectly in sync

    def top(self):
        return self.stack[-1]

    def getMin(self):
        return self.min_stack[-1]
Crucial Notepush onto min_stack the running minimum min(val, previous_min), not val itself. If you stored raw values, popping would expose whatever value happens to sit below — which is not the minimum of what remains. Storing the running min at every level is what lets the correct minimum resurface automatically after a pop. And always pop both stacks together; the instant they fall out of sync, getMin starts lying.
Worked Example:watch the min resurface, including a duplicate
Track (stack, min_stack) tops as we go.
- push(-2) → stack [-2], min_stack [-2].
- push(0) → min(0, -2) = -2. stack [-2, 0], min_stack [-2, -2].
- push(-3) → min(-3, -2) = -3. stack [-2, 0, -3], min_stack [-2, -2, -3].
- getMin() → read min_stack top → -3.
- pop() → drop both tops: stack [-2, 0], min_stack [-2, -2]. The min resurfaces to -2 with zero recomputation.
- top()0. getMin()-2.

The duplicate-minimum case is the one that trips naive fixes: push 0, then 0 again. min_stack holds [0, 0], so after popping one 0 the min is still 0 — correct, because a second copy of the minimum is still in the stack. Storing the min per level handles this for free; a single "remember one min value" variable would wrongly forget it.

What you paid, and the reflex

You bought O(1) on all four operations by spending O(N) extra space on the parallel stack — the familiar trade memory for speed. The reusable idea is broader than the minimum: when a stack must also report some running aggregate — min, max, sum, count — carry that aggregate in a parallel stack that pushes and pops in lockstep. Each level snapshots the aggregate of everything beneath it, so it self-restores on pop. That single pattern answers a whole family of "stack that also tracks X" interview questions.

Interactive Strategy Visualization
MIN STACK ARCHITECTURE

Synchronized dual-stack mechanism

DATA STACK
MIN STACK

Mental Model

  • Why Two Stacks? One stack stores the actual elements. The other stores the "minimum at each state".
  • Consistency: Whenever you pop an element that is the current minimum, you must also pop from the min stack.
LOGICSTEP 1/7
Design a stack that retrieves the minimum in O(1).
STRATEGY

Alternative Implementation

You can also use a single stack that stores pairs of `[value, min_so_far]`. This keeps the same logic but avoids managing two separate data structures.

O(N) Scan Every getMin
O(1) All Ops · Parallel Min-Stack