Trapping Rain Water
Hard · Two Pointers · Explanation and code example
Two Pointers
How it works
Water at any position depends on the shorter wall between the left and right sides. So if the left wall is shorter, the right wall can't help us—water is limited by the left side. That means we safely move the left pointer inward and calculate how much water can be trapped there. Similarly, if the right wall is shorter, we move the right pointer left.
As we move the pointers, we keep track of the highest wall seen so far on each side (leftMax and rightMax).
The water at each position is simply:
max wall on that side – height at that position
Steps
- Set two pointers:
lat the startrat the end TrackleftMaxandrightMaxas the tallest walls seen.
- While
l < r:- If
leftMax < rightMax:- Move
lright. - Update
leftMax. - Add
leftMax - height[l]to the result.
- Move
- Else:
- Move
rleft. - Update
rightMax. - Add
rightMax - height[r]to the result.
- Move
- If
- Return the total trapped water.
Complexity
- Time complexity:
O(n) - Space complexity:
O(1)
Things to watch for
Calculating Water at Boundary Bars
The leftmost and rightmost bars can never hold water above them since there's no wall on one side to contain it. Including them in water calculations gives wrong results.
Using Current Bar Height Instead of Max Heights
Water at each position depends on the minimum of the maximum heights to its left and right, minus the current height. Using the current bar's height in the max comparison instead of tracking running maximums is incorrect.
Negative Water Values
When the current bar is taller than the limiting wall, the water calculation yields a negative value. This happens at peaks and should contribute zero water, not negative.
Wrong Pointer Movement in Two Pointers
In the two-pointer approach, always move the pointer on the side with the smaller max height. Moving the wrong pointer breaks the invariant that the smaller side determines the water level.
Python code example
from typing import List
class Solution:
def trap(self, height: List[int]) -> int:
if not height:
return 0
l, r = 0, len(height) - 1
leftMax, rightMax = height[l], height[r]
res = 0
while l < r:
if leftMax < rightMax:
l += 1
leftMax = max(leftMax, height[l])
res += leftMax - height[l]
else:
r -= 1
rightMax = max(rightMax, height[r])
res += rightMax - height[r]
return res
C++ code example
class Solution {
public:
int trap(vector<int>& height) {
if (height.empty()) {
return 0;
}
int l = 0, r = height.size() - 1;
int leftMax = height[l], rightMax = height[r];
int res = 0;
while (l < r) {
if (leftMax < rightMax) {
l++;
leftMax = max(leftMax, height[l]);
res += leftMax - height[l];
} else {
r--;
rightMax = max(rightMax, height[r]);
res += rightMax - height[r];
}
}
return res;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.