The area between two lines is width * min(height of the two lines) β itβs always capped by the shorter line. That single fact is what lets us skip most pairs without checking them.
Brute Force
Time O(nΒ²)Space O(1)Check every pair of lines and keep the best area.
class Solution: def maxArea(self, height: list[int]) -> int: best = 0 n = len(height) for i in range(n): for j in range(i + 1, n): width = j - i area = width * min(height[i], height[j]) best = max(best, area) return bestCorrect but checks all nΒ²/2 pairs, including many that canβt possibly beat the current best.
Two Pointers
OptimalTime O(n)Space O(1)Start with the widest possible container: pointers at both ends. At each step, the shorter of the two lines is the bottleneck β moving the taller pointer inward can only shrink the width without ever increasing the limiting height, so it can never help. Moving the shorter pointer inward is the only move that has a chance of finding a taller line and a bigger area. So: always move the pointer at the shorter line.
class Solution: def maxArea(self, height: list[int]) -> int: left, right = 0, len(height) - 1 best = 0 while left < right: h = min(height[left], height[right]) best = max(best, h * (right - left)) if height[left] < height[right]: left += 1 else: right -= 1 return bestTracing height = [1,8,6,2,5,4,8,3,7]:
width=8, min(1,7)=1, area=8. Left is shorter β move L.
Why we never miss the true answer: suppose the optimal pair is (i, j). While scanning, whichever of left/right reaches the shorter boundary of the true answer first, the algorithm is forced to move only the other pointer past it β but every pair involving an index outside [i, j] on the discarded side is provably worse (smaller width and capped by the same or shorter height), so nothing optimal is ever skipped.
Complexity: the pointers move toward each other and the loop ends when they meet β O(n) time, O(1) space.