Trapping Rain Water
You're given an array height of non-negative integers that describes an elevation map. Each bar has width 1, and height[i] is the height of the bar at position i, with the bars standing side by side. After it rains, water collects in the dips between bars. Return the total number of units of water trapped. Water runs off past the first and last bars, so nothing is held beyond the two ends.
Examples
height = [0,1,0,2,1,0,1,3,2,1,2,1] returns 6
Index 2 holds 1 unit between the bars of height 1 and 2. Indices 4, 5 and 6 fill up to level 2, holding 1, 2 and 1 units, and index 9 holds 1 unit. That's 1 + 4 + 1 = 6.
height = [4,2,0,3,2,5] returns 9
Everything between the bar of height 4 and the bar of height 5 fills to level 4, the shorter of the two. That puts 2 + 4 + 1 + 2 = 9 units above indices 1 to 4.
Constraints
- n == height.length
- 1 <= n <= 2 * 10^4
- 0 <= height[i] <= 10^5
Hints
Focus on one position. How high can water stand above it, and what on its left and right decides that?
Water at i is min(max height to the left, max height to the right) minus height[i]. Two pointers moving inward from both ends can supply both maxima without extra arrays.
Start l and r at the ends with leftMax = height[l] and rightMax = height[r]. While l < r: if leftMax < rightMax, move l right, update leftMax, and add leftMax - height[l]. Otherwise move r left, update rightMax, and add rightMax - height[r].
Drill This: Your Approach First
Approach
Water above index i is min(tallest bar on its left, tallest bar on its right) minus height[i]. Walk l and r inward from the ends, tracking leftMax and rightMax. If leftMax < rightMax, the right side is already known to have a bar at least that tall, so leftMax is the true level for the next left index: step l, update leftMax, add leftMax - height[l]. Otherwise do the mirror step on the right.
Time
O(n)
Space
O(1)
Pitfall
Solutions
class Solution {
public int trap(int[] height) {
int l = 0, r = height.length - 1;
int leftMax = height[l], rightMax = height[r];
int water = 0;
while (l < r) {
if (leftMax < rightMax) {
l++;
leftMax = Math.max(leftMax, height[l]);
water += leftMax - height[l];
} else {
r--;
rightMax = Math.max(rightMax, height[r]);
water += rightMax - height[r];
}
}
return water;
}
}from typing import List
class Solution:
def trap(self, height: List[int]) -> int:
l, r = 0, len(height) - 1
left_max, right_max = height[l], height[r]
water = 0
while l < r:
if left_max < right_max:
l += 1
left_max = max(left_max, height[l])
water += left_max - height[l]
else:
r -= 1
right_max = max(right_max, height[r])
water += right_max - height[r]
return water