Skip to content

Commit cf07d94

Browse files
committed
refactor(algorithms, two-pointers): trapped rain water
1 parent 6aada08 commit cf07d94

17 files changed

+156
-94
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Trapping Rain-Water
2+
3+
Given an integer array A of non-negative integers representing an elevation map where the width of each bar is 1,
4+
compute how much water it is able to trap after raining.
5+
6+
Input Format
7+
The only argument given is integer array A.
8+
9+
Output Format
10+
Return the total water it is able to trap after raining.
11+
12+
```plain
13+
Example Input
14+
Input 1:
15+
16+
A = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
17+
Input 2:
18+
19+
A = [1, 2]
20+
21+
Example Output
22+
Output 1:
23+
24+
6
25+
Output 2:
26+
27+
0
28+
29+
Example Explanation
30+
Explanation 1:
31+
32+
In this case, 6 units of rain water (blue section) are being trapped.
33+
Explanation 2:
34+
35+
No water is trapped.
36+
```
37+
38+
## Related Topics
39+
40+
- Array
41+
- Two Pointers
42+
- Dynamic Programming
43+
- Stack
44+
- Monotonic Stack
45+
46+
## Solution
47+
48+
We can use the two-pointer technique to solve this problem in O(n) time and O(1) space.
49+
In order for any index in the array to be able to trap rain water, there must be higher bars on both the left and right
50+
side of the index. For example, index 2 in the following array has height 1. It can trap water because there are higher
51+
bars to the left and right of it.
52+
53+
![Solution 1](./images/solutions/trapped_rain_water_solution_1.png)
54+
55+
To calculate the exact amount of water that can be trapped at index 2, we first take the minimum height of the highest
56+
bars to the left and right of it, which in this case is 4. We then subtract the height of the bar at index 2, which is 1,
57+
58+
![Solution 2](./images/solutions/trapped_rain_water_solution_2.png)
59+
60+
So if we knew the height of the highest bars to the left and right of every index, we could iterate through the array
61+
and calculate the amount of water that can be trapped at each index.
62+
But we don't need to know the exact height of both the highest bars to the left and right of every index. For example,
63+
let's say we know the highest bar to the right of index 7 with height 0 has a height of 2.
64+
65+
![Solution 3](./images/solutions/trapped_rain_water_solution_3.png)
66+
67+
If we also knew that there exists a higher bar than 2 anywhere to the left of index 7, then we also know that the minimum
68+
height of the highest bars to the left and right of index 7 is 2. This means that we have enough information to calculate
69+
the amount of water that can be trapped at index 7, which is 2 - 0 = 2.
70+
This is the insight behind how the two-pointer technique can be used to solve this problem. We initialize two pointers
71+
left and right at opposite ends of the array. We also keep two variables leftMax and rightMax to keep track of the highest
72+
bars each pointer has seen.
73+
74+
![Solution 4](./images/solutions/trapped_rain_water_solution_4.png)
75+
76+
We now use the values of leftMax and rightMax to visit every single index in the array exactly once. We start by
77+
comparing leftMax and rightMax. In this case, rightMax is smaller than leftMax, so we know that:
78+
79+
1. The maximum height of the highest bar to the right of right - 1 is rightMax
80+
2. There exists a higher bar than rightMax somewhere to the left of right
81+
82+
These two facts mean that we have enough information to calculate the amount of water that can be trapped at index
83+
right - 1. So first we move the right pointer back by 1:
84+
85+
![Solution 5](./images/solutions/trapped_rain_water_solution_5.png)
86+
87+
There are two possible cases to consider when calculating the amount of water that can be trapped at the current index
88+
of right:
89+
1. The height of the bar at index right is smaller than rightMax
90+
2. The height of the bar at index right is greater than or equal to rightMax
91+
92+
In our case, the height of the bar at index right is smaller than rightMax, so we know that the amount of water that
93+
can be trapped at index 1 is rightMax - height[right], and we can move to the next iteration, which follows the same logic:
94+
95+
![Solution 6](./images/solutions/trapped_rain_water_solution_6.png)
96+
![Solution 7](./images/solutions/trapped_rain_water_solution_7.png)
97+
![Solution 8](./images/solutions/trapped_rain_water_solution_8.png)
98+
![Solution 9](./images/solutions/trapped_rain_water_solution_9.png)
99+
100+
Now, we run into case 2, where height[right] is greater than or equal to rightMax. This means we can't trap any water at
101+
this index, so instead we update rightMax to the height of the bar at index right to prepare for the next iteration.
102+
103+
![Solution 10](./images/solutions/trapped_rain_water_solution_10.png)
104+
![Solution 11](./images/solutions/trapped_rain_water_solution_11.png)
105+
106+
The same logic applies when leftMax is less than rightMax, and this continues until every index has been visited exactly
107+
once, for a total time complexity of O(n) and a space complexity of O(1).
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from typing import List
2+
3+
4+
def trapped_rain_water(heights: List[int]) -> int:
5+
if not heights:
6+
return 0
7+
# Initialize the pointers left and right at both ends of the array
8+
left, right = 0, len(heights) - 1
9+
# initialize left_max and right_max that will keep track of the highest bars each pointer has seen
10+
left_max, right_max = heights[left], heights[right]
11+
# Keeps track of the total trapped rain wayter
12+
result = 0
13+
14+
while left < right:
15+
if left_max < right_max:
16+
left += 1
17+
if heights[left] >= left_max:
18+
left_max = heights[left]
19+
else:
20+
result += left_max - heights[left]
21+
else:
22+
right -= 1
23+
if heights[right] >= right_max:
24+
right_max = heights[right]
25+
else:
26+
result += right_max - heights[right]
27+
return result
29 KB
Loading
45.6 KB
Loading
43.4 KB
Loading
29.4 KB
Loading
26.2 KB
Loading
43.5 KB
Loading
43.5 KB
Loading
43.9 KB
Loading

0 commit comments

Comments
 (0)