Start with the widest possible container, and always give up on the shorter wall — it can never be part of a better answer.
Given an array of heights, height[i] is a vertical wall standing at
index i. Any two walls i and j form a container that holds
(j - i) * min(height[i], height[j]) units of water — width times the
shorter wall, since water spills over the lower side. Find the pair
that holds the most.
Checking every pair is O(n^2). The two-pointer trick gets it down to a single pass by starting at the widest container possible — the two ends — and proving, at each step, that one side can be discarded forever.
Why moving the taller wall never helps
Move the shorter wall
- The current area is capped by
min(left, right). - Moving the taller wall inward only shrinks the width while the cap stays the same or gets worse — it can't beat what you already have.
- Moving the shorter wall is the only move that has a chance of raising the cap.
What it does not prove
- It does not say the shorter wall's next position is better — only that keeping it can never be better.
- It does not generalize to "hold water above every bar" — that's Trapping Rain Water, a different problem with a different invariant.
- "array of heights" or "vertical lines/walls"
- "container" or "maximum water/area between two lines"
- asks for the best pair, not every pair
- width times the shorter side, not the sum of both
The pattern
- 1
Place pointers at index
0andn - 1— the widest span. - 2
Compute the area from the current width and the shorter wall, and keep the best seen so far.
- 3Move the pointer at the shorter wall inward.
- 4Stop when the pointers meet.
Complexity
Each wall is visited at most once as the pointers close in from both ends.
Two pointers and a running max — no auxiliary structures.
Common pitfalls
Moving the taller wall
This is the whole bug surface of the problem — moving the taller wall can only shrink the width without raising the cap, so it silently throws away the correct answer.
Using the sum instead of the shorter wall
Water spills over the lower side. The area is width * min(left, right), not width * (left + right).
Forgetting to record the area before moving
Compute and compare the area at the current pair first, then decide which pointer to move — moving first silently skips positions.
Confusing it with Trapping Rain Water
That problem sums water above every bar and needs the running max from both directions, not just the two outer walls — a plain two-pointer max isn't enough on its own.
Variants worth knowing
- 1
Equal walls — when
leftandrightare the same height, moving either pointer is safe; both are equally capped. - 2
Trapping Rain Water — same opposite-ends setup, but tracks the running max from each side to sum water above every bar, not just the best single pair.
- 3
Two Sum II — the identical "shrink the side that can't improve" proof, applied to a sum instead of an area.

