Min Stack Design in DSA Rust - Time & Space Complexity
We want to understand how fast the Min Stack operations run as we add more items.
How does the time to push, pop, or get the minimum change when the stack grows?
Analyze the time complexity of the following code snippet.
struct MinStack {
stack: Vec,
min_stack: Vec,
}
impl MinStack {
fn push(&mut self, val: i32) {
self.stack.push(val);
if self.min_stack.is_empty() || val <= *self.min_stack.last().unwrap() {
self.min_stack.push(val);
}
}
fn pop(&mut self) {
if let Some(top) = self.stack.pop() {
if top == *self.min_stack.last().unwrap() {
self.min_stack.pop();
}
}
}
fn get_min(&self) -> Option {
self.min_stack.last().copied()
}
}
This code keeps track of the minimum value in the stack at all times using a helper stack.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Each push and pop operation works on the top of the stacks without loops.
- How many times: Each operation runs once per call, no repeated loops inside.
Each push or pop does a fixed number of steps regardless of stack size.
| Input Size (n) | Approx. Operations per push/pop |
|---|---|
| 10 | 2-3 steps |
| 100 | 2-3 steps |
| 1000 | 2-3 steps |
Pattern observation: The number of steps stays about the same no matter how big the stack is.
Time Complexity: O(1)
This means each push, pop, or get_min operation takes the same short time no matter how many items are in the stack.
[X] Wrong: "Finding the minimum must check all items, so it takes longer as the stack grows."
[OK] Correct: The min stack keeps track of minimums as we go, so get_min just looks at the top of min_stack instantly.
Knowing how to keep track of minimums efficiently shows you can design smart data structures that save time.
"What if we stored minimums only when they change, not every time? How would that affect time complexity?"
Practice
Min Stack data structure?Solution
Step 1: Understand the Min Stack concept
A Min Stack is designed to keep track of the minimum element efficiently.Step 2: Identify the key feature
It allows retrieving the minimum element in constant time, unlike a normal stack.Final Answer:
To retrieve the minimum element in constant time -> Option AQuick Check:
Min Stack = fast minimum retrieval [OK]
- Thinking it sorts elements
- Confusing with queue behavior
- Assuming it reverses elements
stack and min_stack?Solution
Step 1: Check Rust vector syntax
Vectors in Rust are declared asVec<Type>, soVec<i32>is correct for 32-bit integers.Step 2: Validate struct field types
struct MinStack { stack: Vec<i32>, min_stack: Vec<i32> } usesVec<i32>for both fields, which is correct syntax and consistent types.Final Answer:
struct MinStack { stack: Vec<i32>, min_stack: Vec<i32> } -> Option CQuick Check:
Vec<i32> syntax = correct struct fields [OK]
- Using array syntax [i32] instead of Vec<i32>
- Omitting type parameters in Vec
- Mixing different integer types
let mut min_stack = MinStack::new();
min_stack.push(3);
min_stack.push(5);
min_stack.push(2);
min_stack.push(1);
min_stack.pop();
println!("{}", min_stack.get_min());Solution
Step 1: Trace push operations and min tracking
Push 3 (min=3), push 5 (min=3), push 2 (min=2), push 1 (min=1).Step 2: Pop removes last pushed element (1), min updates to previous min (2)
After popping 1, minimum is 2.Final Answer:
2 -> Option BQuick Check:
Pop last min updates min to 2 [OK]
- Assuming min stays 1 after pop
- Confusing push order
- Ignoring min stack update on pop
pop method and choose the correct fix:
fn pop(&mut self) {
self.stack.pop();
self.min_stack.pop();
}Solution
Step 1: Understand pop logic in Min Stack
Pop from stack always removes top element. Min stack should only pop if popped element equals current min.Step 2: Identify bug and fix
Current code pops min_stack unconditionally, which breaks min tracking. Fix is to pop min_stack only when needed.Final Answer:
Pop from min_stack only if popped element equals current min -> Option DQuick Check:
Conditional min_stack pop fixes min tracking [OK]
- Popping min_stack unconditionally
- Popping stack twice
- Not handling empty stack cases
push, pop, and get_min all in O(1) time. Which approach below correctly achieves this?Solution
Step 1: Analyze time complexity requirements
All operations must be O(1), so scanning or sorting is too slow.Step 2: Identify data structure approach
Two stacks approach keeps track of minimums efficiently by pushing current min on min_stack during push and popping accordingly.Final Answer:
Use two stacks: one for all elements, one for current minimums updated on push and pop -> Option AQuick Check:
Two stacks = O(1) min tracking [OK]
- Using scanning for min on each call
- Using queue instead of stack
- Sorting after each push
Ready to prove it?
Pass the test and this pattern moves unknown
