Last Updated: March 29, 2026
We need to build a stack, but with a twist: on top of the usual push, pop, and top operations, we also need to retrieve the minimum element at any time, and all of these must run in O(1). The regular stack operations are straightforward. The real challenge is getMin.
If we just had a regular stack, finding the minimum would require scanning every element, which is O(n). The question becomes: how do we keep track of the minimum as elements come and go, without ever needing to scan?
The key observation is that the minimum can only change in two situations: when we push a new element that is smaller than the current minimum, or when we pop an element that was the current minimum. So we need a way to "remember" what the minimum was before that element arrived.
-2^31 <= val <= 2^31 - 1 → Values span the full 32-bit integer range, including Integer.MIN_VALUE. Be careful if using sentinel values.3 * 10^4 calls → Performance is not a concern at this scale, but the problem explicitly requires O(1) per operation, so we need a design-level solution, not brute force.The simplest approach is to use a regular stack for push, pop, and top, and then scan the entire stack whenever getMin is called. This ignores the O(1) requirement but helps us understand the baseline.
Every time someone asks for the minimum, we iterate through all elements currently in the stack and find the smallest one. Push, pop, and top are already O(1) with a standard stack. Only getMin is expensive.
The brute force works but getMin scans the entire stack every time. What if we tracked the minimum as we go, so we never need to scan at all?
Here is the core insight: the minimum of a stack depends only on the elements currently in it, and those elements are always a prefix of our push history (since we only add and remove from the top). So if we record what the minimum was at each "level" of the stack, popping an element automatically reveals the previous minimum.
The cleanest way to do this is with a second stack, often called the min stack. Every time we push a value, we also push the current minimum onto the min stack. When we pop, we pop from both. The top of the min stack always holds the current minimum.
The min stack works because of a simple invariant: at any stack height h, minStack[h] holds the minimum of all elements from the bottom of the stack up to height h. When we pop an element, we reduce the height by one, and the new top of the min stack already has the correct minimum for that reduced height. We precomputed it when we pushed.
This is essentially a prefix minimum over the push history. Since stack operations only affect the top, each prefix minimum is independent of future operations. That is why this approach is both correct and O(1).
stack) and one for tracking minimums (minStack).The two-stack approach gives us O(1) for everything, but we maintain two separate data structures. What if we combined them into a single stack that stores pairs?
Instead of maintaining two separate stacks, we can store pairs of (value, currentMin) in a single stack. Each entry carries its own minimum snapshot. This is functionally identical to the two-stack approach but uses a single data structure, which some find cleaner.
Same principle as the two-stack approach. Each entry in the stack carries a snapshot of the minimum at the time it was pushed. Popping reveals the previous entry, which has its own correct snapshot. The invariant is maintained without any extra coordination, because each pair is self-contained.