150NeetCode 150

22.Min Stack

MediumStack · 2/7

Problem

Design a stack that supports the usual operations and can return the minimum element — all in O(1) time.

Implement the MinStack class:

  • MinStack() initialises the stack.
  • void push(int val) pushes val onto the stack.
  • void pop() removes the top element.
  • int top() returns the top element.
  • int getMin() returns the smallest element currently in the stack.

Examples

Input:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
Output:
[null,null,null,null,-3,null,0,-2]
Explanation:
  push(-2), push(0), push(-3)  → stack [-2, 0, -3]
  getMin() → -3
  pop()                        → stack [-2, 0]
  top()    → 0
  getMin() → -2
Input:
["MinStack","push","push","getMin","pop","getMin"]
[[],[1],[1],[],[],[]]
Output:
[null,null,null,1,null,1]
Explanation: Duplicated minimums must survive a single pop.

Constraints

  • -2^31 <= val <= 2^31 - 1
  • pop, top and getMin are always called on a non-empty stack.
  • At most 3 * 10^4 calls in total.

💡 Key Insight

A stack only changes at its top, so the minimum of the stack below any element never changes while that element is present. Therefore we can record, at push time, "what is the minimum once this element is on the stack?" — and popping simply restores the previous record. No re-scanning is ever needed.

Brute Force (Scan for Minimum)

TimeO(1) for push, pop, top; **O(n)** for getMinSpaceO(n)

Intuition

Store elements in a list; push, pop and top work at the end of the list. For getMin, scan every element.

Algorithm

  1. push: append to the list.
  2. pop: remove the last element.
  3. top: return the last element.
  4. getMin: iterate the whole list and return the smallest value.

Visualization

list = [-2, 0, -3]
getMin → scan -2, 0, -3 → -3     (O(n) every call)

Code

java
import java.util.ArrayList;
import java.util.List;

class MinStack {
    private final List<Integer> data = new ArrayList<>();

    public MinStack() {
    }

    public void push(int val) {
        data.add(val);
    }

    public void pop() {
        data.remove(data.size() - 1);
    }

    public int top() {
        return data.get(data.size() - 1);
    }

    public int getMin() {
        int min = Integer.MAX_VALUE;
        for (int value : data) {
            min = Math.min(min, value); // full scan each time
        }
        return min;
    }
}

Complexity

  • Time: O(1) for push, pop, top; O(n) for getMin — violates the requirement.
  • Space: O(n) — the stored elements.

Complexity Comparison

Approach Time (getMin) Space
Brute Force (scan) O(n) O(n)
Stack of pairs O(1) O(n)
Two stacks (lazy min) O(1) O(n)

Common Pitfalls

  • Pushing to the min stack only when val < min (strict) — after push(1), push(1), pop() the min stack would be empty even though 1 is still on the stack.
  • Comparing stack.pop() == minStack.peek() directly: both are Integer, so == compares references and fails for values outside [-128, 127]. Unbox one side into an int first.
  • Keeping a single min variable — after popping the minimum you have no way to recover the previous one.
  • Using Integer.MAX_VALUE as a sentinel and then mishandling a real pushed value of Integer.MAX_VALUE.