Skip to content

Trapping Rain Water

Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

InputOutput
[0,1,0,2,1,0,1,3,2,1,2,1]6
[4,2,0,3,2,5]9

For height = [0,1,0,2,1,0,1,3,2,1,2,1], water is trapped in the following pockets:

i01234567891011
height010210132121
water001012100100

Total: 0+0+1+0+1+2+1+0+0+1+0+0 = 6

  • n == height.length
  • 1 <= n <= 2×10^4
  • 0 <= height[i] <= 10^5
ApproachTimeSpaceBest When
Two PointersO(n)O(1)Optimal — best for interviews
Prefix Max ArraysO(n)O(n)Conceptually clearest
Monotonic StackO(n)O(n)Process column by column (horizontal thinking)
✓ Simple
⏱ Time O(n) Three linear passes 💾 Space O(n) Two extra arrays

Start here — it’s the most intuitive. Build two arrays: left_max[i] is the tallest bar from the left up to i, and right_max[i] is the tallest bar from the right down to i. The water at each position is min(left_max[i], right_max[i]) - height[i] (clamped to 0). This directly encodes the core insight: water height is limited by the shorter of the two surrounding walls.

Step-by-step for [0,1,0,2,1,0,1,3,2,1,2,1]

Section titled “Step-by-step for [0,1,0,2,1,0,1,3,2,1,2,1]”
iheightleft_maxright_maxmin(l,r)water
000300
111310
201311
322320
412321
502322
612321
733330
823220
913221
1023220
1113110

Total: 6 ✓

Animated walkthrough

Prefix max arrays — building left_max, right_max, then computing water

Use Next or Autoplay to watch the left_max array fill from left to right, then right_max from right to left, then see each water cell computed.

Step 1 of 5
Waiting to begin...
Array state
Memory / lookup state

function trap(height):
n = len(height)
left_max = [0] * n; right_max = [0] * n
left_max[0] = height[0]
for i in 1..n-1: left_max[i] = max(left_max[i-1], height[i])
right_max[n-1] = height[n-1]
for i in n-2..0: right_max[i] = max(right_max[i+1], height[i])
total = 0
for i in 0..n-1: total += max(0, min(left_max[i], right_max[i]) - height[i])
return total
trapping_rain_water_prefix_max.py
"""
Given n non-negative integers representing an elevation map where the width of each
bar is 1, compute how much water it can trap after raining.
Example 1:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Example 2:
Input: height = [4,2,0,3,2,5]
Output: 9
"""
# Approach: Prefix Max Arrays
# Build left_max[i] = max height from height[0] to height[i].
# Build right_max[i] = max height from height[i] to height[n-1].
# Water at i = max(0, min(left_max[i], right_max[i]) - height[i]).
# The minimum of both maxes is the effective wall height that bounds the water.
# Time Complexity: O(n) — three linear passes
# Space Complexity: O(n) — two extra arrays of size n
from typing import List
def trap(height: List[int]) -> int:
n = len(height)
if n == 0:
return 0
left_max = [0] * n
right_max = [0] * n
left_max[0] = height[0]
for i in range(1, n):
left_max[i] = max(left_max[i - 1], height[i])
right_max[n - 1] = height[n - 1]
for i in range(n - 2, -1, -1):
right_max[i] = max(right_max[i + 1], height[i])
water = 0
for i in range(n):
water += max(0, min(left_max[i], right_max[i]) - height[i])
return water
print(trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])) # 6
print(trap([4, 2, 0, 3, 2, 5])) # 9
★ Recommended
⏱ Time O(n) Single pass 💾 Space O(1) Four variables only

The O(1) space optimization over prefix max arrays. Instead of pre-building both arrays, maintain running maxes max_left and max_right as the pointers converge inward.

Why it works: If max_left <= max_right, the water at left is definitely max_left - height[left] — even if right_max is higher, the bottleneck is max_left. We don’t need to know the exact right side. Symmetrically for the right pointer.

stepLh[L]Rh[R]mlmrprocessrunning water
1045500ml<=mr: ml=max(0,4)=4, water+=0, L++0
2125540ml>mr: mr=max(0,5)=5, water+=0, R—0
3124245ml<=mr: water+=4-2=2, L++2
4204245ml<=mr: water+=4-0=4, L++6
5334245ml<=mr: water+=4-3=1, L++7
6424245ml<=mr: water+=4-2=2, L++9

L >= R, done. Answer: 9 ✓

function trap(height):
left, right = 0, len(height) - 1
max_left, max_right = 0, 0
water = 0
while left < right:
if max_left <= max_right:
max_left = max(max_left, height[left])
water += max_left - height[left]
left++
else:
max_right = max(max_right, height[right])
water += max_right - height[right]
right--
return water
trapping_rain_water_two_pointer.py
"""
Given n non-negative integers representing an elevation map where the width of each
bar is 1, compute how much water it can trap after raining.
Example 1:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Example 2:
Input: height = [4,2,0,3,2,5]
Output: 9
"""
# Approach: Two Pointers
# Use left and right pointers, tracking max_left and max_right seen so far.
# Process whichever side has the smaller max — that side's max is the bottleneck.
# water at current position = max_on_that_side - height[current]
# Update max before adding water, then advance the pointer.
# Time Complexity: O(n) — single pass
# Space Complexity: O(1) — four variables only
from typing import List
def trap(height: List[int]) -> int:
left, right = 0, len(height) - 1
max_left, max_right = 0, 0
water = 0
while left < right:
if max_left <= max_right:
max_left = max(max_left, height[left])
water += max_left - height[left]
left += 1
else:
max_right = max(max_right, height[right])
water += max_right - height[right]
right -= 1
return water
print(trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])) # 6
print(trap([4, 2, 0, 3, 2, 5])) # 9
🎯 Interview Favourite
⏱ Time O(n) Each bar pushed and popped once 💾 Space O(n) Stack stores indices

Think horizontally instead of vertically. The stack maintains indices of bars in decreasing height order. When a taller bar appears, we found a right wall. The popped bar is the bottom of the pool. The new stack top is the left wall. Each iteration fills one horizontal layer of water.

Step-by-step for [0,1,0,2,1,0,1,3,2,1,2,1]

Section titled “Step-by-step for [0,1,0,2,1,0,1,3,2,1,2,1]”
ih[i]stack beforeactionwater added
00[]push 00
11[0]h[1]>h[0]: pop 0, stack empty → break; push 10
20[1]h[2]<=h[1]: push 20
32[1,2]h[3]>h[2]: pop 2, left=1, w=1, water+=min(1,2)-0=1; h[3]>h[1]: pop 1, empty→break; push 31
41[3]h[4]<=h[3]: push 40
50[3,4]h[5]<=h[4]: push 50
61[3,4,5]h[6]>h[5]: pop 5, left=4, w=0, skip; h[6]<=h[4]: break; push 60
73[3,4,6]h[7]>h[6]: pop 6, left=4, w=2, water+=min(1,3)-1=0; pop 4, left=3, w=3…3

(Remaining steps accumulate total to 6)

function trap(height):
stack = []
water = 0
for i in range(len(height)):
while stack and height[i] > height[stack[-1]]:
bottom = stack.pop()
if not stack: break
left = stack[-1]
width = i - left - 1
h = min(height[left], height[i]) - height[bottom]
water += h * width
stack.append(i)
return water
trapping_rain_water_stack.py
"""
Given n non-negative integers representing an elevation map where the width of each
bar is 1, compute how much water it can trap after raining.
Example 1:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Example 2:
Input: height = [4,2,0,3,2,5]
Output: 9
"""
# Approach: Monotonic Stack
# Maintain a stack of indices with decreasing heights (a monotonic decreasing stack).
# When height[i] > height[stack.top()], we found a right wall — the pool can be filled.
# Pop the bottom index, compute water between the new stack top (left wall) and i (right wall).
# Think horizontally: each pop fills one horizontal layer of trapped water.
# Time Complexity: O(n) — each bar is pushed and popped at most once
# Space Complexity: O(n) — stack stores indices
from typing import List
def trap(height: List[int]) -> int:
stack: List[int] = []
water = 0
for i in range(len(height)):
while stack and height[i] > height[stack[-1]]:
bottom = stack.pop()
if not stack:
break
left = stack[-1]
width = i - left - 1
bounded_height = min(height[left], height[i]) - height[bottom]
water += bounded_height * width
stack.append(i)
return water
print(trap([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1])) # 6
print(trap([4, 2, 0, 3, 2, 5])) # 9