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.
Example 1:
Input ["MinStack","push","push","push","getMin","pop","top","getMin"] [[],[-2],[0],[-3],[],[],[],[]] Output [null,null,null,null,-3,null,0,-2] Explanation MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.getMin(); // return -3 minStack.pop(); minStack.top(); // return 0 minStack.getMin(); // return -2
Constraints:
-231 <= val <= 231 - 1
pop
, top
and getMin
operations will always be called on non-empty stacks.3 * 104
calls will be made to push
, pop
, top
, and getMin
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for the Min Stack involves keeping track of all the numbers pushed onto the stack. Whenever we need the minimum, we'll simply look through all the numbers we've saved to find the smallest one.
Here's how the algorithm would work step-by-step:
class MinStack:
def __init__(self):
self.stack_list = []
def push(self, value):
# Add the new value to the stack list.
self.stack_list.append(value)
def pop(self):
if self.stack_list:
self.stack_list.pop()
def top(self):
if self.stack_list:
return self.stack_list[-1]
def getMin(self):
# Handle the case where the stack is empty.
if not self.stack_list:
return None
current_minimum = self.stack_list[0]
# Iterate through all elements in the stack.
for element in self.stack_list:
# Compare the element with current minimum
if element < current_minimum:
current_minimum = element
# The min has been found after comparison
return current_minimum
To efficiently find the minimum value at any point in a stack, we'll use an additional stack to track the minimums. Each time we push an element, we check if it's a new minimum and update the minimum stack accordingly. This allows us to retrieve the minimum in constant time.
Here's how the algorithm would work step-by-step:
class MinStack:
def __init__(self):
self.stack = []
self.minimum_stack = []
def push(self, value):
self.stack.append(value)
# Update the minimum stack with the current minimum value
if not self.minimum_stack or value <= self.minimum_stack[-1]:
self.minimum_stack.append(value)
def pop(self):
if not self.stack:
return
popped_value = self.stack.pop()
# If popped is current min, pop from minimum stack too
if popped_value == self.minimum_stack[-1]:
self.minimum_stack.pop()
def top(self):
if self.stack:
return self.stack[-1]
def getMin(self):
# Provides minimum element in stack at O(1) time
if self.minimum_stack:
return self.minimum_stack[-1]
Case | How to Handle |
---|---|
Initial stack is empty and getMin is called | Throw an exception or return a specific error value (e.g., Integer.MAX_VALUE or null) to signal no minimum exists. |
Large number of push operations causing potential memory overflow | Ensure that underlying data structures (e.g., ArrayList, linked list) have dynamic resizing to accommodate a large number of elements; consider memory limitations during design. |
Pushing and popping elements such that the minimum element changes frequently | The auxiliary stack for maintaining minimums ensures O(1) getMin regardless of minimum value fluctuation. |
Stack contains Integer.MIN_VALUE and more values are pushed | Handle Integer.MIN_VALUE carefully to avoid underflow when updating the minimum values; consider using long to represent the minimum if necessary. |
Stack contains duplicate minimum values | Auxiliary stack should correctly track all occurences or equivalents of the true minimum value. |
Calling top on an empty stack | Throw an exception or return a specific error value (e.g., null) to indicate an empty stack. |
Sequence of pushes followed by a sequence of pops that empties the stack. | The minimum stack should be correctly updated after each pop and getMin should function as intended upon each call. |
Negative numbers being pushed onto the stack | The comparison logic needs to work correctly with negative numbers to accurately track the minimum value. |