Trapping Rain Water Using Stack in DSA Rust - Time & Space Complexity
We want to understand how the time needed to calculate trapped rain water changes as the input size grows.
Specifically, we ask: How does the number of steps grow when we use a stack to solve this problem?
Analyze the time complexity of the following code snippet.
fn trap(height: Vec<i32>) -> i32 {
let mut stack = Vec::new();
let mut water = 0;
for i in 0..height.len() {
while !stack.is_empty() && height[i] > height[*stack.last().unwrap()] {
let top = stack.pop().unwrap();
if stack.is_empty() { break; }
let distance = i - stack.last().unwrap() - 1;
let bounded_height = height[i].min(height[*stack.last().unwrap()]) - height[top];
water += distance as i32 * bounded_height;
}
stack.push(i);
}
water
}
This code calculates how much rain water can be trapped between bars using a stack to track boundaries.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: A single loop over the height array with an inner while loop that pops from the stack.
- How many times: Each element is pushed once and popped at most once, so the inner loop runs in total at most n times.
As the input size n grows, each element is processed a limited number of times.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 steps (push and pop combined) |
| 100 | About 200 steps |
| 1000 | About 2000 steps |
Pattern observation: The total steps grow roughly in a straight line with input size, not squared or faster.
Time Complexity: O(n)
This means the time to compute trapped water grows linearly with the number of bars.
[X] Wrong: "The inner while loop makes this algorithm O(n²) because it can run many times for each element."
[OK] Correct: Each element is pushed and popped only once, so the total inner loop runs at most n times, keeping the overall time linear.
Understanding this linear time solution shows you can use stacks smartly to solve tricky problems efficiently, a skill valued in many coding challenges.
"What if we replaced the stack with a simple nested loop approach? How would the time complexity change?"
Practice
Trapping Rain Water Using Stack algorithm?Solution
Step 1: Understand the role of stack in the algorithm
The stack stores indices of bars that are waiting to find a right boundary to trap water.Step 2: Clarify what the stack does not do
The stack does not store water amount or sort bars; it helps find boundaries for trapped water.Final Answer:
To keep track of bars that are not yet processed for water trapping -> Option CQuick Check:
Stack tracks bars for trapping water = D [OK]
- Thinking stack stores water amount
- Assuming stack sorts the bars
- Believing stack reverses bar order
Solution
Step 1: Identify correct stack declaration for indices
Indices are usize type, so stack must be Vec<usize> and mutable to push/pop.Step 2: Check each option
let mut stack: Vec<usize> = Vec::new(); correctly declares mutable Vec<usize> empty stack. let stack = Vec::with_capacity(10); is immutable and no mut keyword. let stack = vec![0]; initializes with one element, not empty. let mut stack: Vec<i32> = Vec::new(); uses i32 instead of usize for indices.Final Answer:
let mut stack: Vec<usize> = Vec::new(); -> Option BQuick Check:
Mutable Vec<usize> empty stack = A [OK]
- Using wrong type like i32 for indices
- Not making stack mutable
- Initializing stack with elements instead of empty
fn trap(height: Vec<i32>) -> i32 {
let mut stack: Vec<usize> = Vec::new();
let mut water = 0;
for i in 0..height.len() {
while !stack.is_empty() && height[i] > height[*stack.last().unwrap()] {
let top = stack.pop().unwrap();
if stack.is_empty() {
break;
}
let distance = i - *stack.last().unwrap() - 1;
let bounded_height = height[i].min(height[*stack.last().unwrap()]) - height[top];
water += (distance as i32) * bounded_height;
}
stack.push(i);
}
water
}
let heights = vec![0,1,0,2,1,0,1,3,2,1,2,1];
println!("{}", trap(heights));Solution
Step 1: Understand the input and algorithm
The input heights represent bars: [0,1,0,2,1,0,1,3,2,1,2,1]. The stack-based algorithm calculates trapped water by finding bounded areas.Step 2: Calculate trapped water step-by-step
The known trapped water for this input is 6 units, as the algorithm sums water trapped between bars correctly.Final Answer:
6 -> Option AQuick Check:
Trapped water for given heights = 6 [OK]
- Miscounting trapped water units
- Ignoring boundary conditions
- Incorrectly calculating distance or height
fn trap(height: Vec<i32>) -> i32 {
let mut stack: Vec<usize> = Vec::new();
let mut water = 0;
for i in 0..height.len() {
while !stack.is_empty() && height[i] > height[*stack.last().unwrap()] {
let top = stack.pop().unwrap();
if stack.is_empty() {
break;
}
let distance = i - *stack.last().unwrap() - 1;
let bounded_height = height[i].min(height[*stack.last().unwrap()]) - height[top];
water += distance * bounded_height;
}
stack.push(i);
}
water
}Solution
Step 1: Identify type mismatch in multiplication
distance is usize, bounded_height is i32; multiplying usize * i32 causes type error in Rust.Step 2: Fix by casting distance to i32 before multiplication
Cast distance as i32: (distance as i32) * bounded_height to fix type mismatch.Final Answer:
Change water += distance * bounded_height; to water += (distance as i32) * bounded_height; -> Option DQuick Check:
Cast usize to i32 before multiply = C [OK]
- Ignoring type mismatch errors
- Removing necessary empty stack check
- Changing comparison operator incorrectly
[4, 2, 0, 3, 2, 5], what is the total trapped rain water calculated by the stack-based algorithm?Solution
Step 1: Visualize the bars and trapped water
Bars heights: 4, 2, 0, 3, 2, 5. Water trapped between bars is calculated by stack algorithm using boundaries.Step 2: Calculate trapped water stepwise
Using min(left_max, right_max) - height[i] for each i:
- i=1: min(4,5)-2=2
- i=2: min(4,5)-0=4
- i=3: min(4,5)-3=1
- i=4: min(4,5)-2=2
Total trapped water = 9 units.Final Answer:
9 -> Option AQuick Check:
Sum trapped water units = 9 [OK]
- Miscounting water units between bars
- Ignoring zero height bars
- Not considering both left and right boundaries
Ready to prove it?
Pass the test and this pattern moves unknown
