Two walls form a container whose capacity is min(h[l], h[r]) × (r − l). Start pointers at both ends and always move the shorter wall inward — moving the taller one could never improve the area, so you explore every promising pair in a single O(n) pass.
Given an array height where each value is a vertical wall, find two walls that, together with the x-axis, hold the most water. The area between walls at indices l and r is min(height[l], height[r]) × (r − l) — the shorter wall is the bottleneck, and the width is the gap. Example: height = [1,8,6,2,5,4,8,3,7] → the pair at indices 1 and 8 (heights 8 and 7) gives area min(8,7) × (8−1) = 7 × 7 = 49.
l = 0, r = n − 1, best = 0. The widest possible pair starts the search.area = min(h[l], h[r]) × (r − l). Update best if larger.h[l] <= h[r], increment l; otherwise decrement r. Moving the taller bar could never produce a better area — the height cap stays the same or drops while width decreases.l >= r. Every pair that could beat the current best has been visited.(l, r) where h[l] <= h[r], every pair (l, r') with r' < r has area <= h[l] × (r' − l) < h[l] × (r − l). So all those pairs are provably worse — skip them by moving r is unnecessary; we move l instead.The two-pointer approach is both time and space optimal. Unlike most two-pointer problems there is no sorting step — the array is used as-is.
l=0, r=8. We'll track the best area seen.function maxArea(height: number[]): number {
let l = 0;
let r = height.length - 1;
let best = 0;
while (l < r) {
const area = Math.min(height[l], height[r]) * (r - l);
if (area > best) best = area;
// Always move the shorter pointer inward.
// Moving the taller one can never increase area —
// width shrinks and height is still capped by the shorter bar.
if (height[l] <= height[r]) {
l++;
} else {
r--;
}
}
return best;
}l and r start at opposite ends, giving the widest possible container. best accumulates the running maximum.best if this pair beats the current record.height[l] <= height[r], the left wall is the bottleneck; move l right. Otherwise move r left. Moving the taller wall inward can only decrease (or maintain) the height cap while the width definitely shrinks — a strictly worse or equal area. The comment in the code captures the exact reason.best.h[l] <= h[r], any pair formed by moving r to r' has area at most h[l] × (r' − l), which is strictly less than h[l] × (r − l) — so we skip it without missing the optimum.bestL and bestR alongside best and update them whenever a new maximum is found.(i, j) pairs is easy to state and obviously correct. The interview insight is recognising that fixed-endpoint pairs in each row are dominated, letting you prune to a single pass.| "most water" / "max container" | two pointers from both ends |
| area = min height × width | move the shorter pointer inward |
| O(n) two-pointer on unsorted array | greedy: discard dominated side |
| "trapping rain water" variant | same pattern, sum instead of max |
let l = 0, r = height.length - 1, best = 0;
while (l < r) {
const area = Math.min(height[l], height[r]) * (r - l);
if (area > best) best = area;
if (height[l] <= height[r]) {
l++;
} else {
r--;
}
}
return best;min(height[l], height[r]) × (r − l) — the shorter wall is the bottleneck; width is the gap.height = [1,8,6,2,5,4,8,3,7], what is the maximum area?height = [4, 4] (two walls of equal height), what is the area?