This is a classic two-pointer optimization problem. The difficulty is not computing an area. It is proving which boundary can be discarded without missing the optimal answer.
Quick Summary
| Signal | What it tells you |
|---|---|
| answer depends on two ends of a range | think opposite-direction pointers |
area uses min(leftHeight, rightHeight) |
the shorter wall is the bottleneck |
| width shrinks every move | any future improvement must come from height |
The key invariant is: once one wall is the shorter side, keeping that same wall while shrinking width cannot produce a better answer.
Problem Statement
Given an array height, choose two indices i and j to form a container.
The amount of water it holds is:
min(height[i], height[j]) * (j - i)
Return the maximum possible area.
Why Brute Force Misses the Pattern
Brute force checks every pair of lines, which is O(n^2).
That works, but it ignores the structure of the formula.
Area depends on two things:
- width:
j - i - limiting height:
min(height[i], height[j])
When we move inward, width always gets smaller. So if a later container is going to be better, the limiting height must improve enough to offset that lost width.
That is the whole reason a linear scan becomes possible.
Optimal Approach
- start with the widest possible container: leftmost and rightmost walls
- compute its area
- move the pointer at the shorter wall
- keep the best area seen so far
Why move the shorter wall? Because it is the current bottleneck. Moving the taller wall keeps the same limiting height while shrinking width, so that move cannot help.
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length - 1;
int best = 0;
while (left < right) {
int h = Math.min(height[left], height[right]);
int w = right - left;
best = Math.max(best, h * w);
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return best;
}
}
Why Moving the Shorter Side Is Correct
Suppose:
- left height =
2 - right height =
10
The current water height is limited by 2.
If we move the right wall inward:
- width gets smaller
- the limiting height is still at most
2
So that move cannot improve the answer.
The only rational hope is to move the shorter wall and search for a taller bottleneck.
Dry Run
Input: [1,8,6,2,5,4,8,3,7]
left=0 (1),right=8 (7)area =1 * 8 = 8moveleftleft=1 (8),right=8 (7)area =7 * 7 = 49best =49moverightleft=1 (8),right=7 (3)area =3 * 6 = 18moveright- continue inward
No later container beats 49, so the answer is 49.
Visual Intuition
left right
v v
[ 1, 8, 6, 2, 5, 4, 8, 3, 7 ]
Current area is limited by the shorter wall.
If that shorter wall stays the same and width shrinks, the area cannot improve.
That is why the shorter wall is the only side worth discarding.
Common Mistakes
- moving both pointers every round
- moving the taller wall by default
- using
left <= rightand evaluating zero-width containers - memorizing the rule without understanding the limiting-height argument
Debug Checklist
- print
left,right, both heights, and area each iteration - test
[1,1]to confirm the smallest valid case - test
[1,8,6,2,5,4,8,3,7]and confirm the answer is49 - say the invariant out loud: the shorter wall is the only useful side to move
Pattern Generalization
This belongs to the same family as:
Two Sum IIValid Palindrome3Sumafter sorting
The common question is: which move safely discards impossible candidates without losing the optimum?
Complexity
- Time:
O(n) - Space:
O(1)
Key Takeaways
- This is a pruning argument disguised as a two-pointer problem.
- The shorter wall is the current bottleneck, so it is the only side worth moving.
- Width always decreases, so later improvement can only come from a better limiting height.
Categories
Tags
Comments