Interview Cracker GitHub

2026-09-22 — Trapping Rain Water

Difficulty: 🔴 Hard Pattern: Two pointers (or a monotonic stack) Time-box: 20 minutes

Problem

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

A column holds water up to the height of the shorter of the tallest bar to its left and the tallest bar to its right — and only if both exist and are taller than the column itself.

Examples

[0, 1, 0, 3, 9, 2, 3, 4, 5, 7, 3, 0, 5] -> 22
[4, 2, 0, 3, 2, 5]                      -> 9
[1, 0, 1]                               -> 1
[]                                        -> 0

Constraints


Hint (open only if stuck after 10 minutes)

Keep two pointers at the ends and two running maxima. On each step, move the pointer under the SMALLER maximum inward: that maximum is the definitive water level for that column, because the far side is at least as tall as it. Add level - height[col] and update the maximum.


Solution
def trap(height: list[int]) -> int:
    left, right = 0, len(height) - 1
    left_max = right_max = 0
    water = 0

    while left < right:
        if height[left] < height[right]:
            # The right side holds a bar at least as tall as left_max
            # will ever need to be: left_max is the binding level here.
            if height[left] >= left_max:
                left_max = height[left]
            else:
                water += left_max - height[left]
            left += 1
        else:
            if height[right] >= right_max:
                right_max = height[right]
            else:
                water += right_max - height[right]
            right -= 1

    return water

How it works. Each column's water level is min(max-to-left, max-to-right). The two-pointer trick avoids computing both maxima for every column: when the left side is the smaller, its maximum is final for that column — the unseen right side cannot lower the minimum below it. So that column is settled in O(1), and the pointer advances.

Complexity. Time: O(n) — each pointer moves at most n steps total. Space: O(1) — two maxima and two pointers.

Edge cases that matter. Empty array and single bar (0 water). Flat arrays and monotone arrays (no basin, 0 water). Deep narrow wells between two huge walls. A column exactly as tall as the binding maximum adds 0 — the >= vs > choice in the update does not matter, but the structure (compare against the CURRENT max, not the bar opposite) does.

Common wrong answer. Using the height of the OPPOSITE pointer as the water level (water += height[right] - height[left] when the left is lower). That works only when the taller pointer happens to sit on the true basin wall; on inputs like [4, 2, 0, 3, 2, 5] where the maximum sits at the very end, it overcounts. The running maxima are what make the per-column level correct no matter where the tallest bars are.