Container With Most Water
Table of Contents + β
Container With Most Water is a classic two-pointer question. It looks like a geometry puzzle. But it is really about a smart way to move two pointers. The interviewer wants to see if you can prove why moving the shorter side is always the right choice.
π― The Problem
You get an array of heights. You have to find the two lines that hold the most water.
- Each number is the height of a vertical line.
- Two lines and the ground form a container.
- The water is the area of the rectangle between the two lines.
- The width is the distance between the lines.
- The height is the shorter of the two lines, because water spills over the shorter wall.
- So area is width times the shorter height.
For heights [1, 8, 6, 2, 5, 4, 8, 3, 7], the best pair is the 8 at index 1 and the 7 at index 8. The width is 8 - 1 = 7. The shorter height is 7. So the area is 7 * 7 = 49.
Input: height = [1, 8, 6, 2, 5, 4, 8, 3, 7]Output: 49
Explanation: lines at index 1 (height 8) and index 8 (height 7). width = 7, shorter height = 7, area = 7 * 7 = 49.Here is the picture. The tall lines are the walls and the gap between two walls holds the water.
π’ Approach 1: Try Every Pair (Brute Force)
The idea in one line: check every possible pair of lines and keep the biggest area.
The idea:
- Pick a left line. Pick a right line.
- Find the area between them.
- Keep the biggest area you have seen.
How it works:
- Two nested loops walk over the array.
- For each pair, compute width times the shorter height.
Why it is weak:
- Two nested loops over n lines means about n times n pairs.
- Time is O(nΒ²). On a long array this is slow.
Here is the brute-force code for that idea:
def max_area(height): best = 0 for left in range(len(height)): for right in range(left + 1, len(height)): width = right - left water = width * min(height[left], height[right]) best = max(best, water) return bestβ‘ Approach 2: Two Pointers (Best)
The idea in one line: start wide, then always close in the shorter wall.
The idea:
- A pointer is a variable holding a position in the array.
- Put one pointer at the first line and one at the last line.
- At the start the lines are as far apart as possible, so the width is largest.
How it works:
- Compute the area for the two current lines. Save it if it is the biggest.
- Then move one pointer inward. Always move the one on the shorter wall.
- Keep going until the two pointers meet.
Why moving the shorter wall is safe:
- The area is capped by the shorter wall.
- Moving the taller wall in keeps the same short cap but shrinks the width. The area can only get worse.
- Moving the shorter wall in gives a chance at a taller wall. The area might rise.
Why it is fast:
- Each pointer moves inward and never goes back.
- Each line is touched once. Time is O(n), space is O(1).
Here is the dry-run for the first few steps on our example.
Steps to Solve
- Put a left pointer at the first line and a right pointer at the last line.
- Set the best area to zero.
- While left is before right, find the width and the shorter height, then compute the area.
- Update the best area if this area is bigger.
- Move the pointer that points to the shorter line one step inward.
- Stop when the pointers meet. Return the best area.
This Python version closes two pointers inward and keeps the largest area.
def max_area(height): left = 0 # pointer at the first line right = len(height) - 1 # pointer at the last line best = 0 while left < right: h = min(height[left], height[right]) # shorter wall limits the water width = right - left best = max(best, h * width) # keep the biggest area if height[left] < height[right]: left += 1 # move the shorter side inward else: right -= 1 return best
height = [1, 8, 6, 2, 5, 4, 8, 3, 7]print(max_area(height))The output of the above code will be:
49Let us walk through the Python version line by line. The key is which pointer moves.
left = 0 and right = len(height) - 1 set the two pointers at the far ends. The width starts at its largest. We try the widest container first.
best = 0 holds the biggest area we have found so far.
while left < right: keeps going until the pointers meet. Once they touch, there is no container left to check.
h = min(height[left], height[right]) picks the shorter of the two walls. Water spills over the shorter wall. So the shorter wall sets the height of the container.
width = right - left is the distance between the two lines. best = max(best, h * width) computes the area and keeps it if it beats the current best.
if height[left] < height[right]: left += 1 moves the left pointer when the left wall is shorter. else: right -= 1 moves the right pointer otherwise. We always move the shorter wall. Moving the taller wall could never raise the area, because the short wall would still cap it and the width would shrink. So moving the shorter wall is the only move with a chance to improve.
β±οΈ Time and Space Complexity
The brute force checks every pair, so it is O(nΒ²) time. The two-pointer version moves each pointer inward and never goes back. So it touches each line once. That makes it O(n) time and O(1) space. We trade a clever proof for a big speed win.
| Approach | Time Complexity | Space Complexity |
|---|---|---|
| Brute force (all pairs) | O(nΒ²) | O(1) |
| Two pointers | O(n) | O(1) |
Tip
The interviewer will ask why moving the shorter side is safe. Be ready to explain it. The short wall caps the area, so moving the tall wall in can only hurt. That proof is the whole point of the question.
π§© Key Takeaways
- β The water height is set by the shorter of the two walls, not the taller one.
- β Start the two pointers at the far ends so the width starts at its largest.
- β Always move the pointer on the shorter wall inward.
- β Moving the taller wall can never raise the area, so it is never the right move.
- β The two-pointer walk runs in O(n) time with O(1) extra memory.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What sets the height of the water in a container?
Why: Water spills over the shorter wall, so the shorter wall caps the height.
- 2
Where do the two pointers start?
Why: Starting at the ends gives the widest possible container as the first try.
- 3
Which pointer do we move inward, and why?
Why: The short wall caps the area, so only moving it gives a chance at a taller wall and more water.
- 4
What is the time and space complexity of the two-pointer solution?
Why: Each pointer moves inward at most n steps total and we store only a few variables.