Min Stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. Implement the MinStack class: MinStack() initializes the stack object. void push(int val) pushes the element val onto the stack. void pop() removes the element on the top of the stack. int top() gets the top element of the stack. int getMin() retrieves the minimum element in the stack. You must implement a solution with O(1) time complexity for each function.
- -2³¹ <= val <= 2³¹ - 1
- pop, top and getMin are always called on a non-empty stack
- At most 3 × 10⁴ calls will be made to push, pop, top, and getMin
push(-2), push(0), push(-3), getMin(), pop(), top(), getMin()-3, 0, -2push(1), push(2), getMin(), pop(), getMin()1, 1push(0), push(1), push(0), getMin(), pop(), getMin()0, 0A stack is naturally great at keeping track of the order of elements. But a standard stack has a secret weakness: it is blind to its own contents. If you want to find the smallest number in a stack of a million items, you have to pop everything out to see them, which destroys the stack and takes O(N) time.
In a regular stack, the minimum is "somewhere inside." To find it without destroying the stack, you'd have to iterate through the entire underlying array. This makes getMin() an O(N) operation. We need to make it O(1).
The key insight is that for any element at position i, the minimum value in the stack at the moment that element was pushed will never change as long as that element is the top.
Think of it like a Time-Traveler's Log:
1. Every time you push a value onto the main stack, you record the "current champion" (the minimum of the whole stack) in a separate auxiliary stack.
2. The auxiliary stack keeps a history of the minimum value for every single state of the main stack.
The two stacks must stay perfectly in sync:
- Push: When a new value arrives, compare it to the current top of the minStack. Push the smaller of the two onto the minStack.
- Pop: When a value is removed from the main stack, its corresponding "minimum at that time" must also be removed from the minStack.
- GetMin: Simply look at the top of the minStack.
1. Maintain two stacks: stack and minStack.
2. Push(x):
- stack.push(x)
- minStack.push(min(x, minStack.top() or infinity))
3. Pop():
- stack.pop()
- minStack.pop()
4. GetMin(): Return minStack.top().
class MinStack:
def __init__(self):
self.stack = []
self.min_stack = []
def push(self, val: int):
self.stack.append(val)
# Current min is the smaller of val and previous top
curr_min = val
if self.min_stack:
curr_min = min(val, self.min_stack[-1])
self.min_stack.append(curr_min)
def pop(self):
self.stack.pop()
self.min_stack.pop()Synchronized dual-stack mechanism
Mental Model
- Why Two Stacks? One stack stores the actual elements. The other stores the "minimum at each state".
- Consistency: Whenever you pop an element that is the current minimum, you must also pop from the min stack.
Alternative Implementation
You can also use a single stack that stores pairs of `[value, min_so_far]`. This keeps the same logic but avoids managing two separate data structures.