Trapping Rain Water (LeetCode 42)
You're given n non-negative integers, height, describing an elevation map made of unit-width bars side by side. Work out how much rain water would settle on top of it after a downpour.
Level 3 | | | | | | | | [█] | | | | | Level 2 | | | | [█] | [~] | [~] | [~] | [█] | [█] | [~] | [█] | | Level 1 | | [█] | [~] | [█] | [█] | [~] | [█] | [█] | [█] | [█] | [█] | [█] | --------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Height | 0 | 1 | 0 | 2 | 1 | 0 | 1 | 3 | 2 | 1 | 2 | 1 | Water | - | - | +1 | - | +1 | +2 | +1 | - | - | +1 | - | - | Legend: [█] = Solid elevation terrain bar (height >= 1) [~] = Trapped rain water (1 unit per block) Total Trapped Water = 1 + 1 + 2 + 1 + 1 = 6 Units ⚠️ Top Interview Gotchas:
- The "Unseen Interior Peaks" Paradox: When
height[left] < height[right], trapped water atleftis strictly bounded byleft_max. Even if an interior mountain of height 10,000 exists between them, it only acts as an even taller barrier; water atleftcan never exceedleft_maxwithout spilling left! - Order-of-Operations (Negative Water Trap): Always update
left_max = max(left_max, height[left])before accumulatingleft_max - height[left]to guarantee non-negative water. - Boundary Elements Never Trap Water: Indices
0andn-1can only act as outer walls, never hold water.
Worked Examples
height = [0,1,0,2,1,0,1,3,2,1,2,1]6height = 0 | left_max = 2 | right_max = 3
Water = min(2, 3) - 0 = 2 units
At any bar, water level is min(left_max, right_max). Water cannot rise higher because it would spill over the shorter side.
If height[left] < height[right], water at left is strictly governed by left_max. We safely advance left++ without knowing interior peaks!
- Unseen Interior Peaks: If
h[L] < h[R], an unseen mountain of height 10,000 in the middle does not change the fact that water atLis capped byleft_max. It can only spill left! - Order-of-Operations Bug: Always update
left_max = max(left_max, h[L])before subtracting to ensure you never add negative water. - Outer Edges Trap Zero: Indices
0andn - 1can never hold water because there are no outer containing walls.
height = [4,2,0,3,2,5]9height = 2 | left_max = 4 | right_max = 5
Water = min(4, 5) - 2 = 2 units
At any bar, water level is min(left_max, right_max). Water cannot rise higher because it would spill over the shorter side.
If height[left] < height[right], water at left is strictly governed by left_max. We safely advance left++ without knowing interior peaks!
- Unseen Interior Peaks: If
h[L] < h[R], an unseen mountain of height 10,000 in the middle does not change the fact that water atLis capped byleft_max. It can only spill left! - Order-of-Operations Bug: Always update
left_max = max(left_max, h[L])before subtracting to ensure you never add negative water. - Outer Edges Trap Zero: Indices
0andn - 1can never hold water because there are no outer containing walls.
⚖️Formal Constraints & Bounds
n == height.length1 <= n <= 2 * 1040 <= height[i] <= 105
Core Insight
When height[left] < height[right], the trapped water at left is strictly bounded by left_max, regardless of any interior peaks.
Real-World Scenario & Production Applications
Terrain flood catchment simulation, civil reservoir engineering, and digital elevation model hydrology mapping.
Subproblems & Recurrence Decomposition3 Phases
Place left = 0, right = len(height) - 1. Maintain running boundary peaks left_max = 0, right_max = 0 and water = 0.
left, right = 0, len(height) - 1
left_max = right_max = water = 0Step-by-Step Execution Trace Table
| Step | left | right | left_max | right_max | Bottleneck | Water Added | Total |
|---|---|---|---|---|---|---|---|
| 1 | 0 (h=0) | 11 (h=1) | 0 | 1 | Left (h[0] < h[11]) | +0 | 0 |
| 2 | 1 (h=1) | 11 (h=1) | 1 | 1 | Right (h[1] >= h[11]) | +0 | 0 |
| 3 | 1 (h=1) | 10 (h=2) | 1 | 2 | Left (h[1] < h[10]) | +0 | 0 |
| 4 | 2 (h=0) | 10 (h=2) | 1 | 2 | Left (h[2] < h[10]) | +1 (1 - 0) | 1 |
| 1 | left, right = 0, len(height) - 1 |
| 2 | left_max, right_max, water = 0, 0, 0 |
| 3 | while left < right: |
| 4 | if height[left] < height[right]: |
| 5 | if height[left] >= left_max: |
| 6 | left_max = height[left] |
| 7 | else: |
| 8 | water += left_max - height[left] |
| 9 | left += 1 |
| 10 | else: |
| 11 | if height[right] >= right_max: |
| 12 | right_max = height[right] |
| 13 | else: |
| 14 | water += right_max - height[right] |
| 15 | right -= 1 |
| 16 | return water |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
The volume of water trapped above any individual bar at index is determined strictly by its confining boundaries: \text{water}[i] = \max(0, \min(\text{max_left}, \text{max_right}) - \text{height}[i]). While prefix and suffix maximum arrays compute this in time and space, two converging pointers achieve the theoretical optimum: time and auxiliary space.
🏟️ The Analogy: The Leaking Bathtub
Imagine a bathtub with irregular stepped walls. Water does not care how high the tallest mountain on earth is; it spills over the lower rim of the tub. If you know with certainty that the left rim is 3 feet high and the right rim is at least 5 feet high, you can calculate the water level at the left edge immediately: water will rise to exactly 3 feet. It does not matter if the right wall is 5 feet, 10 feet, or 100 feet.
🔑 Why It Works
The cognitive leap: when height[left] < height[right], we are guaranteed that left_max < height[right] <= right_max. Therefore, min(left_max, right_max) is definitively left_max. We can safely record the water trapped at left and advance inward without ever needing to know the true value of right_max!
Calculating water before updating running max: Water trapped at
leftisleft_max - height[left]. If you calculate water beforeleft_max = max(left_max, height[left]), negative water values will corrupt the total.Moving the larger boundary: You can only safely compute water at the pointer whose running boundary is strictly smaller than the opposing boundary (
left_max < right_max).Ignoring edge boundaries: Indices
0andlen(height) - 1can never hold water; starting the two-pointer inward scan at0andn - 1correctly enforces zero water on borders.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
Elevation / volume trapping between boundaries with 1D heights.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
Invariant: if height[left] < height[right], water at left is min(left_max, right_max) - height[left] = left_max - height[left].
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
Searching for global peak: unnecessary and wastes
O(N)time or space.
The 60-Second Interview Pitch
Say this out loud before you type a single line
"I initialize left=0, right=len(height)-1, left_max=0, right_max=0. At each step, if height[left] < height[right], left is the bottleneck: I update left_max and add left_max - height[left] to water, then left++. Otherwise I do the symmetric update on right. Runs in
O(N)time andO(1)space."
Complexity & Mathematical Proof
O(N)
Each iteration of the while loop advances either left or right by 1. The two pointers converge from opposite ends in exactly N steps, performing O(1) comparisons and additions per step.
O(1) Auxiliary
Only four scalar variables are stored (left, right, left_max, right_max, and water), requiring strictly O(1) auxiliary space without auxiliary arrays or stacks.
Derivation Progression
Compares outer walls in O(1) to identify which side is the governing elevation ceiling.
Calculates local trapped water and steps the limiting boundary inward.
Variable Definitions
Total number of elevation bars in height array
Memory Architecture & Bounds
O(1) Iterative
O(1) 4 scalar registers
O(1) Trapped water integer
Boundary Best / Worst Cases
single inward pass.
single inward pass.
single inward pass.
Pointer Invariant Transition Progression
Senior SWE Deconstruction & Hardware Caveats
Triggers: "elevation map", "compute how much water it can trap". Bilateral elevation envelope. Trapped water above bar is .
, heights . Requires time and space (replacing the space prefix/suffix arrays with converging pointers).
Monotonically increasing or decreasing elevation profiles (traps zero water). Updating left_max / right_max before computing trapped water prevents negative accumulation.
Trapping Rain Water (LeetCode 42)
You're given n non-negative integers, height, describing an elevation map made of unit-width bars side by side. Work out how much rain water would settle on top of it after a downpour.
Level 3 | | | | | | | | [█] | | | | | Level 2 | | | | [█] | [~] | [~] | [~] | [█] | [█] | [~] | [█] | | Level 1 | | [█] | [~] | [█] | [█] | [~] | [█] | [█] | [█] | [█] | [█] | [█] | --------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ Index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Height | 0 | 1 | 0 | 2 | 1 | 0 | 1 | 3 | 2 | 1 | 2 | 1 | Water | - | - | +1 | - | +1 | +2 | +1 | - | - | +1 | - | - | Legend: [█] = Solid elevation terrain bar (height >= 1) [~] = Trapped rain water (1 unit per block) Total Trapped Water = 1 + 1 + 2 + 1 + 1 = 6 Units ⚠️ Top Interview Gotchas:
- The "Unseen Interior Peaks" Paradox: When
height[left] < height[right], trapped water atleftis strictly bounded byleft_max. Even if an interior mountain of height 10,000 exists between them, it only acts as an even taller barrier; water atleftcan never exceedleft_maxwithout spilling left! - Order-of-Operations (Negative Water Trap): Always update
left_max = max(left_max, height[left])before accumulatingleft_max - height[left]to guarantee non-negative water. - Boundary Elements Never Trap Water: Indices
0andn-1can only act as outer walls, never hold water.
Worked Examples
height = [0,1,0,2,1,0,1,3,2,1,2,1]6height = 0 | left_max = 2 | right_max = 3
Water = min(2, 3) - 0 = 2 units
At any bar, water level is min(left_max, right_max). Water cannot rise higher because it would spill over the shorter side.
If height[left] < height[right], water at left is strictly governed by left_max. We safely advance left++ without knowing interior peaks!
- Unseen Interior Peaks: If
h[L] < h[R], an unseen mountain of height 10,000 in the middle does not change the fact that water atLis capped byleft_max. It can only spill left! - Order-of-Operations Bug: Always update
left_max = max(left_max, h[L])before subtracting to ensure you never add negative water. - Outer Edges Trap Zero: Indices
0andn - 1can never hold water because there are no outer containing walls.
height = [4,2,0,3,2,5]9height = 2 | left_max = 4 | right_max = 5
Water = min(4, 5) - 2 = 2 units
At any bar, water level is min(left_max, right_max). Water cannot rise higher because it would spill over the shorter side.
If height[left] < height[right], water at left is strictly governed by left_max. We safely advance left++ without knowing interior peaks!
- Unseen Interior Peaks: If
h[L] < h[R], an unseen mountain of height 10,000 in the middle does not change the fact that water atLis capped byleft_max. It can only spill left! - Order-of-Operations Bug: Always update
left_max = max(left_max, h[L])before subtracting to ensure you never add negative water. - Outer Edges Trap Zero: Indices
0andn - 1can never hold water because there are no outer containing walls.
⚖️Formal Constraints & Bounds
n == height.length1 <= n <= 2 * 1040 <= height[i] <= 105
Core Insight
When height[left] < height[right], the trapped water at left is strictly bounded by left_max, regardless of any interior peaks.
Real-World Scenario & Production Applications
Terrain flood catchment simulation, civil reservoir engineering, and digital elevation model hydrology mapping.
Subproblems & Recurrence Decomposition3 Phases
Place left = 0, right = len(height) - 1. Maintain running boundary peaks left_max = 0, right_max = 0 and water = 0.
left, right = 0, len(height) - 1
left_max = right_max = water = 0Step-by-Step Execution Trace Table
| Step | left | right | left_max | right_max | Bottleneck | Water Added | Total |
|---|---|---|---|---|---|---|---|
| 1 | 0 (h=0) | 11 (h=1) | 0 | 1 | Left (h[0] < h[11]) | +0 | 0 |
| 2 | 1 (h=1) | 11 (h=1) | 1 | 1 | Right (h[1] >= h[11]) | +0 | 0 |
| 3 | 1 (h=1) | 10 (h=2) | 1 | 2 | Left (h[1] < h[10]) | +0 | 0 |
| 4 | 2 (h=0) | 10 (h=2) | 1 | 2 | Left (h[2] < h[10]) | +1 (1 - 0) | 1 |
| 1 | left, right = 0, len(height) - 1 |
| 2 | left_max, right_max, water = 0, 0, 0 |
| 3 | while left < right: |
| 4 | if height[left] < height[right]: |
| 5 | if height[left] >= left_max: |
| 6 | left_max = height[left] |
| 7 | else: |
| 8 | water += left_max - height[left] |
| 9 | left += 1 |
| 10 | else: |
| 11 | if height[right] >= right_max: |
| 12 | right_max = height[right] |
| 13 | else: |
| 14 | water += right_max - height[right] |
| 15 | right -= 1 |
| 16 | return water |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
The volume of water trapped above any individual bar at index is determined strictly by its confining boundaries: \text{water}[i] = \max(0, \min(\text{max_left}, \text{max_right}) - \text{height}[i]). While prefix and suffix maximum arrays compute this in time and space, two converging pointers achieve the theoretical optimum: time and auxiliary space.
🏟️ The Analogy: The Leaking Bathtub
Imagine a bathtub with irregular stepped walls. Water does not care how high the tallest mountain on earth is; it spills over the lower rim of the tub. If you know with certainty that the left rim is 3 feet high and the right rim is at least 5 feet high, you can calculate the water level at the left edge immediately: water will rise to exactly 3 feet. It does not matter if the right wall is 5 feet, 10 feet, or 100 feet.
🔑 Why It Works
The cognitive leap: when height[left] < height[right], we are guaranteed that left_max < height[right] <= right_max. Therefore, min(left_max, right_max) is definitively left_max. We can safely record the water trapped at left and advance inward without ever needing to know the true value of right_max!
Calculating water before updating running max: Water trapped at
leftisleft_max - height[left]. If you calculate water beforeleft_max = max(left_max, height[left]), negative water values will corrupt the total.Moving the larger boundary: You can only safely compute water at the pointer whose running boundary is strictly smaller than the opposing boundary (
left_max < right_max).Ignoring edge boundaries: Indices
0andlen(height) - 1can never hold water; starting the two-pointer inward scan at0andn - 1correctly enforces zero water on borders.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
Elevation / volume trapping between boundaries with 1D heights.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
Invariant: if height[left] < height[right], water at left is min(left_max, right_max) - height[left] = left_max - height[left].
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
Searching for global peak: unnecessary and wastes
O(N)time or space.
The 60-Second Interview Pitch
Say this out loud before you type a single line
"I initialize left=0, right=len(height)-1, left_max=0, right_max=0. At each step, if height[left] < height[right], left is the bottleneck: I update left_max and add left_max - height[left] to water, then left++. Otherwise I do the symmetric update on right. Runs in
O(N)time andO(1)space."
Complexity & Mathematical Proof
O(N)
Each iteration of the while loop advances either left or right by 1. The two pointers converge from opposite ends in exactly N steps, performing O(1) comparisons and additions per step.
O(1) Auxiliary
Only four scalar variables are stored (left, right, left_max, right_max, and water), requiring strictly O(1) auxiliary space without auxiliary arrays or stacks.
Derivation Progression
Compares outer walls in O(1) to identify which side is the governing elevation ceiling.
Calculates local trapped water and steps the limiting boundary inward.
Variable Definitions
Total number of elevation bars in height array
Memory Architecture & Bounds
O(1) Iterative
O(1) 4 scalar registers
O(1) Trapped water integer
Boundary Best / Worst Cases
single inward pass.
single inward pass.
single inward pass.
Pointer Invariant Transition Progression
Senior SWE Deconstruction & Hardware Caveats
Triggers: "elevation map", "compute how much water it can trap". Bilateral elevation envelope. Trapped water above bar is .
, heights . Requires time and space (replacing the space prefix/suffix arrays with converging pointers).
Monotonically increasing or decreasing elevation profiles (traps zero water). Updating left_max / right_max before computing trapped water prevents negative accumulation.