Trapping Rain Water — Monotonic Stack Layered Fill
Advertisement
Problem Statement
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.
Constraints:
n == height.length1 <= n <= 2 * 10^40 <= height[i] <= 10^5
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6Input: height = [4,2,0,3,2,5]
Output: 9Why This Problem Matters
LeetCode 42 Trapping Rain Water is the most famous monotonic stack hard problem and is asked at Amazon, Google, Meta, Apple, and Microsoft year after year. It admits at least three solutions (precomputed left-max plus right-max arrays, two-pointer, monotonic stack), each illustrating a different paradigm. Recruiters use it to confirm that you can compare solutions on time, space, and conceptual cleanliness.
The monotonic stack solution is the most general and the most extensible — it directly generalizes to Trapping Rain Water II (3D, LeetCode 407 with a heap), to building Largest Rectangle in Histogram intuition, and to many "find boundaries on each side" problems. Mastering this single problem unlocks a tier of FAANG-grade interview readiness.
The Core Insight
Water sits in a basin formed by a left wall and a right wall. For any column i, the water above it is min(maxLeft, maxRight) minus height[i], capped at 0.
Three approaches:
- Precompute leftMax and rightMax arrays — O(n) time and O(n) space.
- Two pointers — O(n) time, O(1) space, exploiting that the smaller side determines the water.
- Monotonic decreasing stack — fills water layer by layer as we scan, O(n) time and O(n) space.
The stack approach: maintain a stack of indices whose heights are non-increasing from bottom to top. When we see a new bar i with height greater than the stack top, the top is the bottom of a basin whose left wall is the new top after popping (or no wall if the stack becomes empty) and whose right wall is i. Compute the trapped water for that horizontal layer and continue.
This is the same skeleton as Largest Rectangle in Histogram but with a different formula for the contribution per pop.
Visual Dry Run
height equals [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1].
We iterate i from 0 to n minus 1. Stack stores indices.
| i | h | stack (top last) | action | water added |
|---|---|---|---|---|
| 0 | 0 | [0] | push | 0 |
| 1 | 1 | [1] (popped 0 since h[0]=0 less than 1) | pop 0, no left wall, push 1 | 0 |
| 2 | 0 | [1, 2] | push | 0 |
| 3 | 2 | h[2]=0 less than 2: pop 2; left=1, h[1]=1, width=3-1-1=1, water += (min(1,2)-0)*1=1; h[1]=1 less than 2: pop 1, no left wall; push 3 | 1 | |
| 4 | 1 | [3, 4] | push | 1 |
| 5 | 0 | [3, 4, 5] | push | 1 |
| 6 | 1 | h[5]=0 less than 1: pop 5; left=4, h[4]=1, width=6-4-1=1, water += (min(1,1)-0)*1=1; h[4]=1 not less than 1, stop; push 6 | 2 | |
| 7 | 3 | pops cascade: pop 6 (h=1, left=4, width=2, water += (min(1,3)-1)*2=0); pop 4 (h=1, left=3, width=3, water += (min(2,3)-1)*3=3); h[3]=2 less than 3: pop 3, no left wall; push 7 | 5 | |
| 8 | 2 | [7, 8] | push | 5 |
| 9 | 1 | [7, 8, 9] | push | 5 |
| 10 | 2 | pop 9 (h=1, left=8, width=10-8-1=1, water += (min(2,2)-1)*1=1); h[8]=2 not less than 2, stop; push 10 | 6 | |
| 11 | 1 | [7, 8, 10, 11] | push | 6 |
Final water equals 6. Matches expected output.
Solution (Optimal)
from typing import List
def trap(height: List[int]) -> int:
stack = [] # indices with non-increasing heights
water = 0
for i, h in enumerate(height):
while stack and height[stack[-1]] < h:
bottom = stack.pop()
if not stack:
break
left = stack[-1]
width = i - left - 1
depth = min(height[left], h) - height[bottom]
water += width * depth
stack.append(i)
return waterfunction trap(height) {
const stack = [];
let water = 0;
for (let i = 0; i < height.length; i++) {
while (stack.length && height[stack[stack.length - 1]] < height[i]) {
const bottom = stack.pop();
if (!stack.length) break;
const left = stack[stack.length - 1];
const width = i - left - 1;
const depth = Math.min(height[left], height[i]) - height[bottom];
water += width * depth;
}
stack.push(i);
}
return water;
}Complexity. Time O(n) — each index is pushed and popped at most once. Space O(n) for the stack.
Common Mistakes
- Using strict greater-than only when popping. Equal-height bars are not basins, but you must still push to keep the stack monotonic.
- Forgetting to break out of the while loop when the stack becomes empty after popping the bottom — there is no left wall, so no water adds for this layer.
- Confusing the depth formula. The correct formula is min(left height, right height) minus bottom height, not min(left, right).
- Mixing the layered (stack) approach with the two-pointer approach mid-solution.
- Returning the count of pops or the maximum layer instead of the cumulative water.
Interview Tips
- State all three approaches (precomputed arrays, two pointers, monotonic stack) up front. Pick one based on what the interviewer wants — if they want the cleanest code use two-pointer, if they want the most general approach use the stack.
- Walk through the dry run to make the layered fill concrete, especially the cascade of pops at i = 7 in the example.
- Mention that the stack approach generalizes to Trapping Rain Water II (3D) by replacing the stack with a min-heap.
- Reference Largest Rectangle in Histogram as a sibling problem with the same skeleton but different per-pop formula.
- If asked, derive the time bound: each index pushed once and popped once.
Follow-up Questions
- What if the elevation map can change dynamically? Use a segment tree of (max, water) values and recompute affected ranges on update.
- Trapping Rain Water II (3D)? Use a min-heap seeded with all border cells; expand inward, accumulating water.
- What if widths are not all 1? Multiply width by per-cell width; use cumulative width arrays.
- What about negative heights? Treat them as basin floors; the formula still works.
- How would you parallelize over a giant elevation map? Partition into chunks; compute per-chunk trapped water plus merge boundary regions.
Key Takeaways
- A monotonic decreasing stack fills water layer by layer in O(n).
- For each pop, the trapped water rectangle has width equal to right-index minus left-index minus 1 and depth equal to min(left height, right height) minus popped height.
- The two-pointer approach gives the same O(n) time with O(1) space; the stack is more general.
- Pattern generalizes to Trapping Rain Water II (heap), Largest Rectangle in Histogram, and many "boundary on each side" problems.
- Time O(n), space O(n) for the stack.
- This is the signature FAANG monotonic stack problem — master it and many derivatives become accessible.
Advertisement