Design a stack that reports its minimum in O(1)

Keep a second stack of minimums. On push, copy the value onto it whenever it is less than or equal to the current minimum; on pop, remove it from both if it was the top of both. min() is then one read. The <= is the whole question — strictly less breaks on duplicates.

Stacks & queuesCoding problemMedium

Step through it

What to watch

  • The min stack holds one entry per level at which the minimum changed, not one per element.
  • Pushing 1 twice pushes 1 onto the min stack twice — that is what <= buys.
  • After the pop, the minimum is still 1, because the second copy is underneath.

Say this out loud

"A second stack holding the minimum at each level. Push copies the value onto the min stack when it is less than or equal to the current minimum; pop removes it from the min stack if it matches. min() is the top of that stack, so it is O(1). The trap is using strictly less than, which loses a duplicate minimum on the first pop."

Overview

A min stack supports push, pop, top, and minimum lookup in constant time. Store enough history alongside each pushed value so removing the current minimum reveals the previous one without rescanning the data.

Run it

Both versions of the comparison, on the sequence that separates them.

1Python
Output

The min stack grows only when the minimum changes, which is the honest answer to how much extra space it costs.

2Python
Output

And the pair variant: easier to get right, at a fixed cost per element.

3Python
Output

Why a scan is not allowed

The obvious min() walks the stack, which is O(n) and is exactly what the question forbids. Caching a single minimum in a variable is the next attempt and it fails on pop: when the minimum is removed, there is nothing to fall back to, and finding the new one is another scan.

So the structure has to remember the minimum at every level. A parallel stack does that: entry k is the minimum of the first k pushes, so popping a level restores the previous answer for free.

The <= that everybody gets wrong first

Push 2, then 1, then 1. With < the min stack is [2, 1]; with <= it is [2, 1, 1]. Now pop once. Both versions remove a 1 from the data, and the strictly-less version also removed its only 1 from the min stack — so it reports 2 while a 1 is still in the stack.

The editor below runs both and prints the two answers side by side. It is the single most common bug in this question, and an interviewer who asks for duplicates is asking about exactly this line.

The one-stack variants

Two alternatives come up as follow-ups, and both are worth knowing.

Store pairs. Push (value, min_so_far) and the minimum is stack[-1][1]. Simpler to get right, and it costs one extra number per element rather than one per new minimum — worse in the best case, identical in the worst.

Store deltas. Keep one stack and push the difference from the current minimum, tracking the minimum in a variable. It is O(1) extra space, it is genuinely clever, and it is fiddly enough that mentioning it as an option scores better than attempting it under time pressure.

What the question is testing

Whether you can turn "report an aggregate cheaply" into "keep the aggregate as part of the structure". That is the transferable idea: the same move gives a queue with O(1) minimum (two deques, the monotonic one), a sliding-window maximum, and a stack that reports its sum. The interviewer usually follows with one of those.

The second thing being tested is whether you volunteer the duplicate case yourself. Saying "I will use <= so equal minimums each get an entry" before being asked is the answer they are listening for.

Edge cases to raise

Volunteering these is most of what separates a correct answer from a good one.

min() on an empty stack. Decide whether it raises or returns a sentinel, and say which before writing it - an IndexError from self.mins[-1] is a reasonable answer if it is deliberate.

Space is proportional to how often the minimum changes, not to n. An ascending sequence leaves the min stack at length 1; a descending one makes it as long as the data. Worth stating, because it is the honest answer to "how much extra space?"

The two stacks must stay in step. Any method that touches data without considering mins - a clear(), a bulk load, a __setitem__ - is where this class breaks later.

Sources and next steps

How the code works

Both versions of the comparison, run on the sequence that separates them, then the pair variant and a size where a scanning min() stops being viable.

How the code works

  1. if not self.mins or x <= self.mins[-1]The <= is the answer to the question. With <, two equal minimums share one entry and the first pop takes it away from both of them.
  2. if self.mins and v == self.mins[-1]Pop from the min stack only when the value leaving is the current minimum. Popping unconditionally would desynchronise the two stacks immediately.
  3. s.mins -> one entry per level where the minimum changedNot one per element. Pushing an ascending sequence leaves the min stack at length 1, which is the best case for space.
  4. current = x if not self.stack else min(x, self.stack[-1][1])The pair variant computes the running minimum once per push and stores it alongside. Easier to write correctly under pressure, at a fixed two slots per element.

Change one thing

  • Change <= back to < in MinStack and run the ascending sequence (1, 2, 3). Both versions agree there, which is why the bug survives a casual test.
  • Add a max() as well. One more parallel stack, and the same >= question arrives in mirror image.

Where this runs

Real CPython, compiled to WebAssembly and running on your own machine — nothing is uploaded. The first run takes a few seconds while the interpreter downloads; after that it is immediate. Need more room, or want to paste your own attempt? Use the Python compiler.

Check yourself

0 of 4

Answer without scrolling back up.

  1. Why keep a second stack rather than a single minimum variable?

  2. Why is the comparison on push <= rather than <?

  3. How long is the min stack after pushing 1, 2, 3?

  4. What does the pair variant trade?

Cheat sheet

Design a stack that reports its minimum in O(1)

Design a stack that reports its minimum in O(1). Track the minimum at every push and see why a single extra variable is not enough.

INTERVIEW · vizlearn.in/interview/design-a-min-stack.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.