Trapping Rain Water

Problem

Given an array height representing an elevation map where the width of each bar is 1, return the total amount of rainwater trapped after raining.

  • n == height.length
  • 1 ≤ n ≤ 2 * 10⁴
  • 0 ≤ height[i] ≤ 10⁵

Example

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6

The algorithm uses two pointers starting at the ends of the array. Initially, left pointer is at index 0 with height 0, and right pointer at index 11 with height 1. The left_max is 0 and right_max is 1. Since left_max < right_max, move left pointer to index 1 (height 1), update left_max to 1, and add trapped water (1 - 1 = 0). Next, left_max (1) is not less than right_max (1), so move right pointer to index 10 (height 2), update right_max to 2, and add trapped water (2 - 2 = 0). The process continues, moving pointers inward and accumulating trapped water based on the minimum of left_max and right_max. The critical insight is that water trapped at any position depends on the smaller of the maximum heights to its left and right. By moving the pointer with the smaller max inward, the algorithm ensures all trapped water is counted efficiently in a single pass.

Approach

Straightforward Solution

A brute-force approach calculates, for each bar, the maximum height to its left and right, then sums the minimum of these two minus the bar's height. This requires O(n^2) time due to nested scans, which is inefficient for large inputs.

Core Observation

The amount of water trapped at any position depends on the minimum of the maximum heights to its left and right minus the height at that position. This is a fundamental property of the problem and the basis for any solution.

Path to Optimal

Precomputing left_max and right_max arrays reduces time to O(n) but uses O(n) space. The key insight is that by using two pointers starting at both ends and tracking left_max and right_max on the fly, the algorithm can decide which pointer to move based on which side has the smaller max height. This allows the trapped water calculation to be done in a single pass with O(1) extra space.

Optimal Approach

Initialize two pointers at the start and end of the array, along with left_max and right_max as the heights at these pointers. While the pointers do not meet, move the pointer with the smaller max height inward, update the max height for that side, and accumulate trapped water as the difference between the max height and the current bar height. This greedy approach guarantees all trapped water is counted correctly in O(n) time and O(1) space.

Time

O(n)

Each pointer moves inward at most n times, resulting in a single pass through the array.

Space

O(1)

Only a fixed number of variables are used to track pointers and maximum heights, with no additional data structures proportional to input size.

Pattern Spotlight

Two Pointers (Greedy Contraction)

The logic of any optimal Two Pointers solution lies in finding the condition that allows you to permanently discard one end of the search space by moving the pointer that is the current 'limiting factor' to the solution.

Solution

1class Solution:
2 def trap(self, height: list[int]) -> int:
3 if not height:
4 return 0
5
6 l, r = 0, len(height) - 1
7 left_max, right_max = height[l], height[r]
8 res = 0
9
10 while l < r:
11 if left_max < right_max:
12 l += 1
13 left_max = max(left_max, height[l])
14 res += left_max - height[l]
15 else:
16 r -= 1
17 right_max = max(right_max, height[r])
18 res += right_max - height[r]
19
20 return res

Step-by-Step Solution

1

Initialize Two Pointers and Maximum Heights

6l, r = 0, len(height) - 1
7left_max, right_max = height[l], height[r]
8res = 0

Objective

To set up the initial state for the two-pointer traversal, including pointers at both ends and their corresponding maximum heights.

Key Insight

Starting with pointers at the array boundaries and initializing left_max and right_max to the heights at these positions establishes the initial known boundaries for trapping water. This setup is crucial because it allows the algorithm to compare and move pointers inward based on these max heights, enabling the greedy contraction strategy.

Interview Quick-Check

Core Logic

Initializing left_max and right_max to the heights at the pointers ensures the algorithm always knows the current limiting heights on both sides.

State & Boundaries

Pointers start at indices 0 and len(height) - 1, covering the entire array.

2

Move Pointers Inward and Accumulate Trapped Water

10while l < r:
11 if left_max < right_max:
12 l += 1
13 left_max = max(left_max, height[l])
14 res += left_max - height[l]
15 else:
16 r -= 1
17 right_max = max(right_max, height[r])
18 res += right_max - height[r]

Objective

To iteratively move the pointer with the smaller max height inward, update max heights, and accumulate trapped water based on the difference between max height and current bar height.

Key Insight

The greedy choice to move the pointer with the smaller max height inward is based on the fact that trapped water is limited by the smaller boundary. By updating the max height on that side and adding the difference to the result, the algorithm correctly counts trapped water at each step without revisiting positions. This approach avoids the need for extra arrays and achieves O(1) space complexity.

Interview Quick-Check

Core Logic

At each step, move the pointer with the smaller max height inward, update that max height, and add the trapped water (max height - current height) to the result.

State & Boundaries

Continue until the two pointers meet, ensuring all positions are processed.

Common Pitfalls & Bugs

Failing to update max heights before calculating trapped water can lead to incorrect results.

3

Return Total Trapped Water

20return res

Objective

To return the accumulated total amount of trapped rainwater after processing all bars.

Key Insight

After the two pointers meet, all positions have been evaluated for trapped water. Returning the accumulated result provides the final answer to the problem.

Interview Quick-Check

Core Logic

Returning the accumulated result after the loop completes gives the total trapped water.

Line Analysis

This solution has 3 Critical lines interviewers watch for.

Line 11 Critical
if left_max < right_max:

Compare left_max and right_max to decide which pointer to move.

This comparison is the core greedy decision that guarantees correctness: moving the pointer with the smaller max height ensures that the trapped water calculation is bounded by a known limiting height, preventing undercounting or overcounting.

Line 14 Critical
res += left_max - height[l]

Add trapped water at the left pointer position to the result.

This line performs the essential calculation of trapped water at the current position, leveraging the updated left_max to ensure correctness and completeness of the total.

Line 18 Critical
res += right_max - height[r]

Add trapped water at the right pointer position to the result.

This line is the counterpart to the left side calculation and is critical for accumulating trapped water correctly on the right side.

Line 7 Core
left_max, right_max = height[l], height[r]

Initialize left_max and right_max to the heights at the pointers.

Tracking the maximum heights seen so far on each side is essential for determining trapped water at each position.

Line 13 Core
left_max = max(left_max, height[l])

Update left_max to the maximum of current left_max and new height at left pointer.

Updating left_max maintains the highest boundary on the left side, which is critical for accurate trapped water calculation.

Line 17 Core
right_max = max(right_max, height[r])

Update right_max to the maximum of current right_max and new height at right pointer.

Maintaining the highest boundary on the right side is necessary for correct trapped water calculation.

Line 3 Core
if not height:

Check if the input height array is empty.

An empty array means no bars exist to trap water, so the result is zero immediately.

Line 10 Core
while l < r:

Loop while left pointer is less than right pointer.

The loop condition ensures all positions between the pointers are processed exactly once.

Line 20 Core
return res

Return the total trapped water accumulated.

After processing all positions, returning the result provides the final answer to the problem.

Line 6 Standard
l, r = 0, len(height) - 1

Initialize left and right pointer at the start and end of the array respectively.

Starting the left pointer at index 0 sets the initial boundary for the left side of the trapping region. Starting the right pointer at the last index sets the initial boundary for the right side of the trapping region.

Line 12 Standard
l += 1

Increment the left pointer to move inward.

Moving the left pointer inward explores the next bar on the left side, where trapped water may accumulate.

Line 15 Standard
else:

Else branch: move the right pointer inward.

When right_max is less or equal, moving the right pointer inward explores the next bar on the right side.

Line 16 Standard
r -= 1

Decrement the right pointer to move inward.

Moving the right pointer inward allows the algorithm to process bars from the right side towards the center.

Line 4 Standard
return 0

Return 0 when the height array is empty.

This early return prevents unnecessary computation and handles edge cases gracefully.

Line 8 Standard
res = 0

Initialize the result accumulator for trapped water.

This variable accumulates the total trapped water as the algorithm progresses.

Test Your Understanding

Why does moving the pointer with the smaller max height guarantee that all trapped water is accounted for correctly?

Because the trapped water at the pointer depends on the smaller of the two max heights, moving the pointer with the smaller max height ensures that the boundary limiting the trapped water is known and fixed, allowing safe calculation of trapped water at that position without missing any contributions.

Related Problems

Two Pointers pattern

Don't just read it. Drill it.

Reconstruct Trapping Rain Water from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Trapping Rain Water drill

or drill a free problem