Trapping Rain Water Problem in DSA Rust - Time & Space Complexity
We want to understand how the time needed to solve the Trapping Rain Water problem changes as the input size grows.
Specifically, how the number of operations depends on the number of bars in the height array.
Analyze the time complexity of the following code snippet.
fn trap(height: Vec<i32>) -> i32 {
let n = height.len();
let mut left_max = vec![0; n];
let mut right_max = vec![0; n];
for i in 1..n {
left_max[i] = left_max[i - 1].max(height[i - 1]);
}
for i in (0..n-1).rev() {
right_max[i] = right_max[i + 1].max(height[i + 1]);
}
let mut water = 0;
for i in 0..n {
let min_height = left_max[i].min(right_max[i]);
if min_height > height[i] {
water += min_height - height[i];
}
}
water
}
This code calculates how much water can be trapped between bars represented by the height array.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Three separate loops each running through the array once.
- How many times: Each loop runs approximately n times, where n is the number of bars.
As the number of bars increases, the total operations grow roughly in direct proportion.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 30 operations (3 loops x 10) |
| 100 | About 300 operations (3 loops x 100) |
| 1000 | About 3000 operations (3 loops x 1000) |
Pattern observation: The operations increase linearly as input size grows.
Time Complexity: O(n)
This means the time to solve the problem grows in a straight line with the number of bars.
[X] Wrong: "Because there are nested loops in some solutions, this code must be O(n²)."
[OK] Correct: This code uses three separate single loops, not nested loops, so it only grows linearly with input size.
Understanding this linear time solution shows you can optimize problems by avoiding nested loops, a key skill in coding interviews.
"What if we combined the two loops that build left_max and right_max into one? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem context
The problem involves an array representing heights of bars where water can be trapped between them.Step 2: Identify what is asked
We need to find how much water can be trapped after raining, which depends on the heights and gaps between bars.Final Answer:
The total amount of water that can be trapped between the bars after raining -> Option AQuick Check:
Trapping Rain Water = Total trapped water [OK]
- Confusing trapped water with total height sum
- Ignoring gaps between bars
- Only finding tallest bar instead of trapped water
Solution
Step 1: Identify Rust vector syntax
In Rust, vectors are created using vec![elements], which is dynamic and growable.Step 2: Check each option
let heights = vec![0,1,0,2,1,0,1,3,2,1,2,1]; uses vec! macro correctly; B is an array, C is a tuple, D is invalid syntax.Final Answer:
let heights = vec![0,1,0,2,1,0,1,3,2,1,2,1]; -> Option BQuick Check:
vec! macro creates vector [OK]
- Using array syntax instead of vector
- Using tuple parentheses instead of brackets
- Using curly braces which are invalid here
fn trap(height: Vec<i32>) -> i32 {
let mut left = 0;
let mut right = height.len() - 1;
let mut left_max = 0;
let mut right_max = 0;
let mut water = 0;
while left < right {
if height[left] < height[right] {
if height[left] > left_max {
left_max = height[left];
} else {
water += left_max - height[left];
}
left += 1;
} else {
if height[right] > right_max {
right_max = height[right];
} else {
water += right_max - height[right];
}
right -= 1;
}
}
water
}
fn main() {
let heights = vec![0,1,0,2,1,0,1,3,2,1,2,1];
println!("{}", trap(heights));
}Solution
Step 1: Understand two-pointer approach in code
The code uses two pointers from left and right, tracking max heights and accumulating trapped water.Step 2: Trace the example input
For input [0,1,0,2,1,0,1,3,2,1,2,1], the trapped water calculated is 6 units.Final Answer:
6 -> Option AQuick Check:
Two-pointer trap water = 6 [OK]
- Miscounting trapped water units
- Confusing left_max and right_max updates
- Off-by-one errors in pointer movement
fn trap(height: Vec<i32>) -> i32 {
let mut left = 0;
let mut right = height.len();
let mut left_max = 0;
let mut right_max = 0;
let mut water = 0;
while left < right {
if height[left] < height[right] {
if height[left] > left_max {
left_max = height[left];
} else {
water += left_max - height[left];
}
left += 1;
} else {
if height[right] > right_max {
right_max = height[right];
} else {
water += right_max - height[right];
}
right -= 1;
}
}
water
}Solution
Step 1: Check initialization of right pointer
right is set to height.len(), which is out of bounds for indexing (max index is len()-1).Step 2: Correct right initialization
right should be height.len() - 1 to point to the last valid index.Final Answer:
right should be initialized to height.len() - 1 -> Option DQuick Check:
Indexing error fixed by right = len()-1 [OK]
- Using len() as index causes runtime panic
- Changing loop condition incorrectly
- Starting max heights at wrong values
[4,2,0,3,2,5], what is the total trapped rain water using the two-pointer approach?Solution
Step 1: Analyze heights and max boundaries
Left max starts at 4, right max at 5. Water trapped depends on min(left_max, right_max) minus current height.Step 2: Calculate trapped water step-by-step
Positions: - index 1: min(4,5)=4, height=2, trapped=2 - index 2: min(4,5)=4, height=0, trapped=4 - index 3: min(4,5)=4, height=3, trapped=1 - index 4: min(4,5)=4, height=2, trapped=2 Total trapped water = 2+4+1+2 = 9 units. Verified with two-pointer simulation.Final Answer:
9 -> Option CQuick Check:
Two-pointer trap water for [4,2,0,3,2,5] = 9 [OK]
- Adding trapped water incorrectly at edges
- Confusing left_max and right_max updates
- Forgetting to move pointers properly
Ready to prove it?
Pass the test and this pattern moves unknown
