Container With Most Water

Choose two vertical lines that maximize width × the shorter wall. The no-slant rule makes the limiting height explicit.

The memory hook

Start wide; discard the shorter wall, because width can only shrink and the taller wall cannot help until the shorter side improves.

MediumTwo pointers · GreedyO(n) timeO(1) space
01

The shorter wall is the bottleneck

intuition

For endpoints L and R, the container holds (R − L) × min(height[L], height[R]). Begin with maximum width, then throw away only a wall that currently limits the height.

1Start at the edgesThis gives the largest possible width, so every skipped pair must be ruled out deliberately.
2Score the pairThe shorter endpoint sets the waterline; interior lines do not change this pair’s capacity.
3Move the shorter sideKeeping it while narrowing the width cannot improve the area. Only replacing it can raise the limiting height.
The one sentence to remember: At every pair, the shorter wall is the only side that can unlock a taller container.
02

Watch the search space collapse

playable trace

Each frame evaluates one pair, records its area, and advances exactly one pointer. The bars marked as the best container stay highlighted while the active pointers move inward.

Playable trace · Two pointers · Greedy
Frames are generated from the same logic as the code below.
Presets
Current event
Ready — press Play
Best area
0
Pointers
The two pointers start at the widest possible container. Evaluate the pair, then only the shorter wall can move.
unread current active pointer moved out best container
0 / 0
03

A one-pass proof in code

the solution
Python · Two pointers · Greedy
class Solution:
    def maxArea(self, height: list[int]) -> int:
        left, right = 0, len(height) - 1
        best = 0

        while left < right:
            width = right - left
            waterline = min(height[left], height[right])
            best = max(best, width * waterline)

            if height[left] <= height[right]:
                left += 1
            else:
                right -= 1

        return best

The area is measured before the move. On a tie, moving either side is safe; this version advances the left pointer.

Left boundaryleft += 1 when height[left] ≤ height[right]The left wall is the limiting height, so every pair that keeps it has both smaller width and no taller limiting wall.
Right boundaryright -= 1 when height[right] < height[left]Symmetrically, discard the right wall when it is shorter; a better area needs a taller right endpoint.
Widthright - leftEvery move narrows the container by at least one index, so the only hope of improvement is discovering a taller short side.
Why can we skip all pairs that keep the shorter wall? Their width is smaller than the current pair, while their height is still capped by that same shorter wall. Therefore none can beat the current area; moving the taller wall would only make both factors no better.
TimeO(n)Each pointer moves only inward and never reverses, so there are at most n − 1 evaluations.
SpaceO(1)Only two indices and the best answer are maintained; the input array is not copied.
04

Two quick mental checks

make it stick
[1, 8, 6, 2, 5, 4, 8, 3, 7]
max area = 49

The winning endpoints are indices 1 and 8: width 7 and limiting height min(8, 7) = 7.

[4, 3, 2, 1, 4]
max area = 16

The equal outer walls survive as the best pair: width 4 × height 4. The tempting middle walls only reduce both width and height.

What to say out loud
“Area is width times the shorter endpoint. I start with the widest pair and move only the shorter endpoint, because keeping it while shrinking width cannot help. Each pointer moves once, so the scan is linear and constant-space.”