Problem overview
The method maxArea receives an array height of non-negative integers. Entry i is a vertical line at position i with that height. Pick any two lines: together with the x-axis they form a container. The amount of water it holds is the area of a rectangle. The width is the distance between the two lines, and the height is the shorter of the two lines, because water above it would spill over. The method returns the largest area any pair can hold.
For [1, 8, 6, 2, 5, 4, 8, 3, 7] the best pair is the line of height 8 at index 1 and the line of height 7 at index 8. The width is 7, the height is min(8, 7) = 7, and the area is 49.
Approach: start wide and move the shorter line
Checking every pair takes O(n²) time. Two pointers do it in one pass.
Start with the widest container: left at the first line and right at the last. Compute its area. Now one of the pointers must move inward, which makes the container narrower. Which one?
The shorter line caps the height. If you move the taller line inward, the width shrinks and the height is still capped by the same shorter line, or by something even shorter. The new container can't be larger. So the only move that could ever help is to move the shorter line, hoping to meet a taller one. This is safe: every container that uses the shorter line with any partner further in is narrower and no taller, so it can be skipped without being checked.
Repeat until the pointers meet, remembering the best area seen. Each step moves one pointer, so the loop runs at most n - 1 times.
A quick trace on [1, 8, 6, 2, 5, 4, 8, 3, 7]: the first container is lines 1 and 7, with area min(1, 7) * 8 = 8. The left line is shorter, so left moves to the 8. Now min(8, 7) * 7 = 49 is the best so far. The right line is shorter, so right moves in, and the narrower containers that follow never beat 49.
Why does discarding lose nothing? Say the left line, at position a, is not taller than the right line, at position r. Any other container that uses line a has its other line somewhere between a and r, so it is narrower than the one just measured. Its height is also capped by line a, which is the same cap. So its area is at most the area already recorded, and line a can be dropped.
Step by step
- Set up the variables on one line:
resultat 0,leftat 0 andrightatheight.count - 1. - Loop while
left < right. When they meet, there is no pair left. - Compute the area as
min(height[left], height[right]) * (right - left): the shorter line times the distance. - Keep the best with
max(result, area), soresultnever goes down. - Move the shorter side. If
height[left]is smaller thanheight[right], advanceleft. - Otherwise, pull
rightback. This branch also covers equal heights, where moving either pointer is safe. - Return
result.
The solution in Swift
class Solution {
func maxArea(_ height: [Int]) -> Int {
var result = 0, left = 0, right = height.count - 1
while left < right {
let area = min(height[left], height[right]) * (right - left)
result = max(result, area)
if height[left] < height[right] {
left += 1
} else {
right -= 1
}
}
return result
}
}
Swift details worth knowing:
- Global
minandmax. They are free functions that take two values, with no receiver and no import. - Several variables in one declaration.
var result = 0, left = 0, right = height.count - 1declares threeIntvariables. They are allvar, since all three change. let areais a constant created fresh on each pass of the loop.- No
++or--. Swift usesleft += 1andright -= 1. - Overflow. Swift traps on integer overflow rather than wrapping, but an area only overflows a 64-bit
Intfor heights in the billions combined with billions of lines, so it isn't a practical concern here.
Complexity
Time: O(n). Each iteration moves one pointer one step toward the other, so the loop ends after at most n - 1 iterations, and each iteration does constant work.
Space: O(1). Only a few integers are used, whatever the size of the input.
Edge cases and common mistakes
- Two lines.
[1, 1]gives 1: the width is 1 and the height is 1. - Zero heights.
[0, 0]gives 0. A container whose shorter line has height 0 holds nothing. - A tall line in the middle.
[1, 2, 1]gives 2. The two outer lines holdmin(1, 1) * 2 = 2, and the tall middle line can't help because the water is limited by the outer ones. - Tall lines at the ends.
[4, 3, 2, 1, 4]gives 16, the widest container with both lines of height 4. - Using the taller line for the height. The result would count water that spills over.
- Moving the taller pointer. It can skip the best pair for good.
- Forgetting the width. The width is
right - left, not the number of lines. - Fewer than two lines. The lesson promises at least two. If an empty array were passed,
rightwould be -1, the loop would not run and the method would return 0.
Testing
[1, 8, 6, 2, 5, 4, 8, 3, 7]gives49.[1, 1]gives1.[4, 3, 2, 1, 4]gives16.[1, 2, 1]gives2.[0, 0]gives0.

