42. Trapping Rain Water¶
Edited by Charles
Hard · Python · Monotonic Stack
Problem
Read the original problem on LeetCode.
The official page contains the problem statement, examples, and constraints.
Explanation, examples & other approaches
Core idea
Given an array height, where each element represents the height of a bar, compute how much rainwater can be trapped after raining.
Original study notes follow, including intermediate snippets and earlier attempts.
Idea¶
Given an array height, where each element represents the height of a bar, compute how much rainwater can be trapped after raining.
For example:
Output:
Although this problem can be solved using prefix maximum arrays or two pointers, it can also be solved elegantly with a monotonic stack.
The key observation is:
Whenever we find a bar that is higher than the current stack top, a "container" (or valley) is formed, and we can calculate the trapped water immediately.
Unlike the prefix maximum solution, the monotonic stack computes the trapped water layer by layer (horizontally).
Monotonic Stack¶
Why Use a Stack?¶
For every bar, we need to determine:
- the first higher bar on its left
- the first higher bar on its right
Once both boundaries are known, the trapped water can be computed.
A monotonic stack helps us find these boundaries in O(n) time.
What Should Be Stored in the Stack?¶
The stack stores indices.
Whenever the height is needed, simply access
The indices are also required to compute the width.
What Kind of Monotonic Stack?¶
We maintain a monotonically increasing stack of heights.
That means:
Equivalently,
For example,
Whenever a higher bar appears, it closes one or more valleys.
How Is Water Computed?¶
Suppose we pop one element from the stack.
The popped element is the bottom of the valley.
After popping:
- the new stack top is the left wall
- the current index is the right wall
Therefore:
The width is
So the trapped water is
State Transition¶
During traversal, there are three situations.
Case 1: Current bar is lower¶
If
the current bar cannot close any valley.
Simply push its index.
Case 2: Current bar has the same height¶
If
the current implementation simply pushes the new index.
Some implementations replace the previous index with the current one because using the rightmost bar simplifies width calculation. Both approaches can produce correct results with the appropriate implementation.
Case 3: Current bar is higher¶
If
then one or more valleys are completed.
Continue popping while the current bar is taller.
The popped element becomes the valley bottom.
If the stack is empty after popping, there is no left boundary.
Otherwise,
Compute the trapped water.
Height:
Width:
Area:
Finally,
push the current index.
Example¶
Initialization:
i = 1¶
Push.
i = 2¶
Push.
i = 3¶
Pop:
Left boundary:
Right boundary:
Water:
Continue.
Pop again.
Left boundary:
Right boundary:
Water:
Current water:
Push index 3.
Continue until the traversal finishes.
Final answer:
Complexity Analysis¶
Time Complexity
Each index is pushed and popped at most once.
Space Complexity
The stack may contain all indices in the worst case.
Summary¶
Data Structure
Stack Content
Monotonic Property
Water Formula
height = min(left_height, right_height) - bottom_height
width = right - left - 1
water = height * width
Traversal Order
Final Answer
Common Mistakes¶
- Store indices, not heights. The indices are needed to compute the width.
- After popping the valley bottom, always check whether the stack is empty. If it is, there is no left boundary, so no water can be trapped.
- The trapped water height is
not
- The width is
not
because the two boundary bars are not included.
- Continue popping while the current bar is higher than the stack top.
A single higher bar may complete multiple valleys.
- This problem computes trapped water horizontally, one valley at a time, rather than calculating the water above each bar individually.
Why Can the Three Cases Be Simplified?¶
Similar to LeetCode 739 (Daily Temperatures), we can initially analyze three situations when processing a new bar.
Case 1: Current bar is lower¶
The current bar cannot close any valley.
Simply push it into the stack.
Case 2: Current bar has the same height¶
Some implementations replace the previous index with the current one, because using the rightmost bar may simplify width calculation.
However, simply pushing the new index also works correctly.
Case 3: Current bar is higher¶
A valley is completed.
The stack top becomes the valley bottom, and the current bar becomes the right boundary.
We repeatedly pop the stack and calculate trapped water.
Why Can We Merge the Three Cases?¶
Notice that Cases 1 and 2 actually perform the same action:
Neither case computes any trapped water.
Only Case 3 performs additional work by repeatedly popping the stack.
Therefore, instead of writing
if height[i] < height[stack[-1]]:
stack.append(i)
elif height[i] == height[stack[-1]]:
stack.append(i)
else:
while ...
we can directly write
This works because:
- If the current bar is lower, the
whilecondition is false, so we simply push it. - If the current bar is equal, the
whilecondition is also false, so we simply push it. - Only when the current bar is higher does the
whileloop execute and compute trapped water.
As a result, the three explicit cases naturally collapse into a much cleaner implementation.
Study record
| Field | Value |
|---|---|
| Attempts | 1 |
| Mastery | ❚ |
| The Latest Attempt | August 15, 2026 |
Python solution¶
class Solution:
def trap(self, height: List[int]) -> int:
stack = [0]
res = 0
for i in range(1, len(height)):
while len(stack) != 0 and height[stack[-1]] < height[i]:
mid = height[stack.pop()]
if stack:
h = min(height[stack[-1]], height[i]) - mid
w = i - stack[-1] - 1
res += h * w
stack.append(i)
return res