LeetCode #155 Medium

Min Stack

Min Stack is LeetCode 155 (Medium). Design a stack that supports getMin alongside the usual operations:

  • push(val) puts val on top.
  • pop() removes the top element.
  • top() returns the top element without removing it.
  • getMin() returns the smallest element currently in the stack.

Every operation must run in O(1) time. pop, top and getMin are only called on a non-empty stack. Values span the full 32-bit range, and there are up to 3 × 10⁴ calls, so a scan inside getMin is too slow.

Constraints
  • -2³¹ <= val <= 2³¹ - 1
  • Methods pop, top and getMin operations will always be called on non-empty stacks.
  • At most 3 * 10⁴ calls will be made to push, pop, top, and getMin.
stackdesign
Open on LeetCode ↗
02

Intuition

A normal stack already gives O(1) push, pop and top. The hard part of min stack is how to get minimum element from stack in O(1) after a pop: if the minimum is removed, what is the new one? Scanning is O(n), and a single min variable forgets the old minimum.

The key observation is that a stack only changes at its top. While a value sits in the stack, everything below it stays exactly the same, so the minimum of that value and everything beneath it is fixed the moment it is pushed. Store that minimum alongside the value, and every older minimum is still there when the top is popped.

How to spot this pattern

When a data structure must answer a summary query (min, max, sum) in O(1) and only changes at one end, cache the summary per entry at the moment it is added. The same trick gives a max stack, and two such stacks build a queue with O(1) amortised getMin (the sliding-window minimum idea).

03

Approach

Try it first

Before reading on, push 5, 3, 7, 3, then pop twice, and write what getMin must return after each step. Decide what extra information a pop needs to get this right.

1

Store pairs

Each stack entry is (value, min so far), where min so far is the smallest value in this entry and everything beneath it. In the min stack Python code each entry is a tuple; C++ uses pair<int, int> and Java an int[2].

2

push(val)

  • Empty stack – the minimum is val itself.
  • Otherwise – the minimum is min(val, top's min).

Push (val, that minimum). Comparing with the top's stored minimum is enough, because that one number already summarises every element below it.

3

pop(), top(), getMin()

  • pop() – remove the top pair. Its minimum leaves with it, and the pair below still holds the correct older minimum.
  • top() – return the value half of the top pair.
  • getMin() – return the min half of the top pair.
4

Why every operation is O(1)

Each method reads or writes only the top entry, with one comparison at most. No loop depends on the stack size, so all four operations are constant time. Space is O(n): two numbers per element.

04

Min Stack solution in Python | C++ | Java

▶1class MinStack:
▶2 def __init__(self):
▶3 # Each entry is (value, minimum of this entry and all below it).
▶4 self.stack = []
▶5 
▶6 def push(self, val: int) -> None:
▶7 low = min(val, self.stack[-1][1]) if self.stack else val
▶8 self.stack.append((val, low))
▶9 
▶10 def pop(self) -> None:
▶11 self.stack.pop()
▶12 
▶13 def top(self) -> int:
▶14 return self.stack[-1][0]
▶15 
▶16 def getMin(self) -> int:
▶17 return self.stack[-1][1]
stackvalueminemptyoperationsreturnspush −2push 0push −3getMinpoptopgetMin
stack[ ]each entry: (value, min so far)
Idea. A stack only ever changes at the top, so the minimum of the stack below any entry never changes while that entry is there. Store that minimum next to each value, and getMin is just a look at the top pair.
stackvaluemin−2−2← topoperationsreturnspush −2push 0push −3getMinpoptopgetMin
val-2
min so far-2first entry: its own value
Push -2 onto an empty stack. It is the only value, so it is also the minimum: store (-2, -2).
stackvaluemin−2−20−2← topoperationsreturnspush −2push 0push −3getMinpoptopgetMin
val0
min so far-2min(0, -2)
Push 0. The minimum of everything under it is -2, so the new minimum is min(0, -2) = -2, unchanged. Store both, in O(1).
stackvaluemin−2−20−2−3−3← topoperationsreturnspush −2push 0push −3getMinpoptopgetMin
val-3
min so far-3min(-3, -2)
Push -3. The minimum of everything under it is -2, so the new minimum is min(-3, -2) = -3: a new record. Store both, in O(1).
stackvaluemin−2−20−2−3−3← topoperationsreturnspush −2push 0push −3getMin−3poptopgetMin
getMin()-3min half of the top pair
getMin() reads the min half of the top pair: -3. No scan of the stack's 3 values is needed, which is what makes it O(1).
stackvaluemin−2−20−2← top−3−3poppedoperationsreturnspush −2push 0push −3getMin−3poptopgetMin
removed(-3, -3)
min now-2read from the new top
Pop removes -3 together with its stored minimum. It was the minimum, yet nothing has to be searched: the new top already remembers -2, the minimum before -3 arrived. A single min variable could not recover that.
stackvaluemin−2−20−2← topoperationsreturnspush −2push 0push −3getMin−3poptop0getMin
top()0value half of the top pair
top() returns the value half of the top pair, 0, without removing it. O(1).
stackvaluemin−2−20−2← topoperationsreturnspush −2push 0push −3getMin−3poptop0getMin−2
getMin()-2min half of the top pair
getMin() reads the min half of the top pair: -2. No scan of the stack's 2 values is needed, which is what makes it O(1).
stackvaluemin−2−20−2← topoperationsreturnspush −2push 0push −3getMin−3poptop0getMin−2
returned-3, 0, -2from top() and getMin()
every callO(1)
Done. Every operation touched only the top of the stack, so each one ran in O(1) time. The price is one extra number per entry: O(n) space in total.
05

Two-stack min stack

values is an ordinary stack. mins holds only the values that were a new or equal minimum when pushed, so its top is always the current minimum, and it is popped only when that value leaves values.

▶1class MinStack:
▶2 def __init__(self):
▶3 self.stack = []
▶4 self.mins = []
▶5 
▶6 def push(self, val: int) -> None:
▶7 self.stack.append(val)
▶8 if not self.mins or val <= self.mins[-1]:
▶9 self.mins.append(val)
▶10 
▶11 def pop(self) -> None:
▶12 if self.stack.pop() == self.mins[-1]:
▶13 self.mins.pop()
▶14 
▶15 def top(self) -> int:
▶16 return self.stack[-1]
▶17 
▶18 def getMin(self) -> int:
▶19 return self.mins[-1]
06

Common pitfalls

Keeping one min variable

✗ Wrong
def push(self, val):
    self.stack.append(val)
    self.low = min(self.low, val)
✓ Right
def push(self, val):
    low = min(val, self.stack[-1][1]) if self.stack else val
    self.stack.append((val, low))

After popping the current minimum there is no way to know the previous one without scanning. Push 3, 1, pop: a single variable still says 1.

Two stacks that skip equal minimums

✗ Wrong
if val < self.mins[-1]:
    self.mins.append(val)
✓ Right
if val <= self.mins[-1]:
    self.mins.append(val)

In the two-stack version the min stack must also take duplicates. Push 0, 1, 0 then pop: with < the second 0 never reached the min stack, so popping it also pops the first 0's entry, and the min stack is empty while a 0 is still in the stack.

Scanning for the minimum in getMin

✗ Wrong
def getMin(self):
    return min(self.stack)
✓ Right
def getMin(self):
    return self.stack[-1][1]

min(self.stack) is O(n), which fails the O(1) requirement and times out on 3×10⁴ calls.

07

Edge cases

Values near INT_MIN and INT_MAX

Pairs store values as they are, with no arithmetic, so nothing can overflow. The encoded one-stack variant computes 2·val − min, which overflows a 32-bit int here.

08

Complexity

Time
O(1) per operation
Space
O(n)
Every method touches only the top entry, which is exactly what the Min Stack LeetCode problem asks for. Each element stores one extra integer, its running minimum.
09

Three ways to build a min stack

All three give O(1) operations. They differ in how much extra memory they use and how easy they are to get right.

DesignExtra spaceWatch out for
Stack of (value, min) pairs (this page)one int per elementnothing: simplest to prove correct
Value stack + min stackonly when the minimum changes or repeatspush to the min stack on <=, not <
One stack, encoded values (2·val − min)one variableoverflow on large values; hard to explain
10

Min Stack FAQ

Can a min stack use only O(1) extra space?

Yes, by keeping a single min variable and pushing an encoded value 2·val − min whenever val is a new minimum; on pop, a top below min signals the old minimum is 2·min − top. It saves memory but needs 64-bit arithmetic to avoid overflow, and it is much harder to explain in an interview. The pairs-based min stack solution on this page is the safer choice.