📖 4 min read
Last updated on

Min Stack — Coding Interview Walkthrough


Min Stack is one of those problems where the solution is short but the reasoning matters more than the code. Interviewers aren’t checking whether you can write a stack — they’re checking whether you understand why tracking the minimum at each depth works, and whether you can articulate the LIFO insight that makes it possible.


The Problem

Design a stack that supports push, pop, top, and getMin — all in O(1) time. getMin() must return the minimum element in the stack at any time.

Example

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   // → -3
minStack.pop();
minStack.top();      // → 0
minStack.getMin();   // → -2

Already comfortable with the solution? Practice it in a mock interview →


What Interviewers Are Actually Testing

SkillWhat Interviewers Observe
Auxiliary state insightDo you think to track the minimum alongside each element?
Stack LIFO reasoningDo you understand that when you pop a min, the previous min restores?
O(1) constraintDo you avoid scanning the stack to find the minimum?
Design clarityIs your class interface clean and well-encapsulated?

Step 1: Clarifying Questions

  1. Must all operations be O(1)? Yes — this is the core constraint.
  2. What if pop is called on an empty stack? Assume operations are always valid per problem constraints.
  3. Can there be duplicate minimum values? Yes — handle this correctly or getMin breaks on pop.

Step 2: The Naive Idea

Use a regular stack. For getMin, scan the entire stack and return the minimum. O(n) per getMin call — violates the constraint.


Step 3: The Key Insight

Store the current minimum alongside each element. Every time you push, record what the minimum was at that moment. When you pop, the previous minimum is automatically restored because LIFO reverses the push order. No scanning required.

Two vertical stacks side by side: values stack [-2, 0, -3] with top pointer and minimums stack [-2, -2, -3] with min pointer — pink highlighted top shows current minimum -3. ---

Step 4: Optimal Strategy

Use a single stack of (value, current_min) tuples — or use two parallel stacks.

Approach A — Stack of tuples:

  • Push (val, min(val, current_min)).
  • getMin() reads the second element of the top tuple.

Approach B — Two stacks:

  • Main stack holds values.
  • Min stack holds the current minimum at each depth.

Python Implementation

Stack of tuples (cleaner):

class MinStack:
    def __init__(self):
        self.stack = []  # (value, current_min)

    def push(self, val: int) -> None:
        current_min = min(val, self.stack[-1][1]) if self.stack else val
        self.stack.append((val, current_min))

    def pop(self) -> None:
        self.stack.pop()

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

    def getMin(self) -> int:
        return self.stack[-1][1]

Two parallel stacks:

class MinStack:
    def __init__(self):
        self.stack = []
        self.min_stack = []

    def push(self, val: int) -> None:
        self.stack.append(val)
        min_val = min(val, self.min_stack[-1]) if self.min_stack else val
        self.min_stack.append(min_val)

    def pop(self) -> None:
        self.stack.pop()
        self.min_stack.pop()

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

    def getMin(self) -> int:
        return self.min_stack[-1]

Both are O(1) per operation and O(n) space total.


Time & Space Complexity

OperationTimeSpace
pushO(1)O(1) per element
popO(1)
topO(1)
getMinO(1)
Total spaceO(n)

Common Interview Mistakes

  1. Storing only the global minimum. If you pop the minimum, your stored value is now wrong. You need the minimum at every stack depth.

  2. Not handling the empty stack edge case in push. When the stack is empty, current_min = val (no previous min to compare against).

  3. Duplicates. If -3 is pushed twice and popped once, getMin should still return -3. Both approaches handle this correctly because they track min per push, not per unique value.

  4. Forgetting both stacks must pop together. In the two-stack approach, forgetting to pop min_stack in pop() desyncs them.


What a Strong Candidate Sounds Like

“The O(1) constraint rules out scanning on getMin. The insight is that the minimum is a function of what’s currently in the stack. If I track ‘what is the minimum so far’ at each level when I push, then getMin is just reading the top of that min record. When I pop, the previous level’s minimum automatically becomes current. I’ll use a stack of (value, current_min) tuples.”


Example Interview Dialogue

Interviewer: Why does storing the minimum at each level work when you pop?

Candidate: Because of LIFO ordering. When I push, I snapshot the current minimum. When I pop that element, every element below it was pushed before it, so the minimum of those elements hasn’t changed. The snapshot from the element below is still correct.

Interviewer: Would a single variable tracking the current min work?

Candidate: No. When I pop the current minimum, I’d need to scan the entire stack to find the new minimum. That’s O(n). The per-level approach avoids this entirely because each level already knows its own minimum.



Practice This in a Mock Interview

Min Stack is deceptively simple — the code is short, but explaining why the LIFO property makes per-level minimum tracking work is what separates strong candidates from weak ones.

Start a mock interview for Min Stack on Intervu.


Further reading:

Practice Like It's the Real Interview

Get instant feedback on your approach, communication, and code — powered by AI.

Start a Mock Interview →