Example 1
ready- Input
height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ]- Expected
6- Why
- the separate pockets hold 1 + 1 + 2 + 1 + 1 units
After a storm, a jagged rooftop can hold surprising pockets of water. The trick is measuring every pocket without pouring the rain into a simulation.
An elevation map is an array where height[i] gives the height of a
one-unit-wide vertical bar at position i. Given that map, return the total number
of water units trapped between the bars after rain falls.
A few ground rules:
0 <= height.length <= 20_0000 <= height[i] <= 10_000200_000_000, safely within the judge's integer
range.Hints
For one index, find the tallest bar on its left and the tallest bar on its right. The shorter boundary decides the waterline; subtract the current bar's height.
A prefix maximum is the tallest bar seen so far from the left; a suffix maximum is the same idea from the right. Storing both removes the repeated scans. Can you keep only the boundary information needed at this moment?
Put one pointer at each end. When the left bar is no taller than the right bar, the
right side already supplies a sufficient boundary for the left position, so update
left_max, add any water there, and move left inward. Mirror that rule on the
other side.
Can you reach O(n) time and O(1) extra space without building prefix or suffix arrays?
Visible cases
height = [
0,
1,
0,
2,
1,
0,
1,
3,
2,
1,
2,
1
]6height = [
5,
4,
3,
2,
1
]0height = [
4,
2,
0,
3,
2,
5
]9Interview signal
At position i, water rises only as high as the shorter of the tallest bars to
its left and right. Scan both directions to find those two boundaries, then subtract
height[i].
def trap(height: list[int]) -> int:
total = 0
n = len(height)
for i in range(n):
left_max = 0
for left in range(i + 1):
left_max = max(left_max, height[left])
right_max = 0
for right in range(i, n):
right_max = max(right_max, height[right])
total += min(left_max, right_max) - height[i]
return totalIncluding the current bar in both scans keeps the contribution non-negative. The answer is correct, but almost every boundary gets rediscovered many times.
Time O(n²) — each of n positions may scan the whole map. Space O(1) — only the two maxima and the running total are stored.
Move left and right inward while carrying the tallest bar seen from each
side. If height[left] <= height[right], the right side already has a boundary at
least as tall as the current left bar. That makes the left position safe to settle:
height[left] reaches a new left_max, it holds no water.left_max - height[left] units.When the right bar is lower, the same reasoning settles the right position using
right_max.
def trap(height: list[int]) -> int:
left = 0
right = len(height) - 1
left_max = 0
right_max = 0
total = 0
while left < right:
if height[left] <= height[right]:
left_max = max(left_max, height[left])
total += left_max - height[left]
left += 1
else:
right_max = max(right_max, height[right])
total += right_max - height[right]
right -= 1
return totalEach decision finalizes one position. You never need to revisit it because the lower side's available boundary — not the unknown interior — is what limits that position.
Time O(n) — one pointer moves on every iteration. Space O(1) — four indices or running values are enough.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
6