How to Explain Container With Most Water in a Coding Interview (Step-by-Step)
Container With Most Water is a two-pointer problem where the hardest part isn’t the code — it’s justifying the greedy decision. Why do we always move the shorter line? If you can explain that clearly, you’ve cracked the interview.
In this post, you’ll learn exactly how to walk an interviewer through this problem: how to visualise it, how to justify the pointer movement, and which edge cases to call out proactively.
Problem Statement
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container that holds the most water. Return the maximum amount of water a container can store.
Examples
Output: 49
Explanation: Lines at index 1 (height 8) and index 8 (height 7) → min(8,7) × (8-1) = 7 × 7 = 49
Output: 1
Constraints
n == height.length2 <= n <= 10⁵0 <= height[i] <= 10⁴
What Is the Problem?
“I have an array of heights representing vertical lines. I need to pick two lines that, together with the x-axis, form the container with the maximum water capacity. The water capacity is the width between the lines multiplied by the shorter of the two heights — because water can only fill up to the shorter wall.”
Step 1: Start With the Brute Force (Then Dismiss It)
Try every pair of lines — O(n²) pairs
Time: O(n²)
Space: O(1)
Too slow for n = 10⁵
Start at both ends, greedily move inward
Time: O(n)
Space: O(1)
Single pass — optimal
The Key Insight
Start with the widest possible container — pointers at both ends. Width can only decrease as we move inward, so to have any chance of finding a larger area, we must find a taller line.
The shorter line is the bottleneck — it caps the height. Moving the shorter pointer inward is the only move that could possibly increase the area. Moving the taller one can only make things worse.
The Greedy Decision — Why Always Move the Shorter Line?
This is the question interviewers always ask. Be ready with a clear proof:
Width decreases. Height is still capped by the shorter line (which didn’t move). Area can only stay the same or get smaller. No benefit.
Width decreases. But now we might find a taller line that increases the height cap enough to compensate. The only chance of improvement.
“At every step, we’re making the locally optimal choice — discard the side that can’t possibly lead to a better answer. This is a greedy approach, and it works because moving the taller line is provably never better than moving the shorter one.”
Step 3: Explain the Algorithm in Plain English
“I place one pointer at the leftmost line and one at the rightmost. At each step I compute the current area, update the maximum, then move the pointer pointing to the shorter line inward. I repeat until the pointers meet. The maximum area seen is the answer.”
Step 4: Talk Through the Code
class Solution:
def maxArea(self, height: List[int]) -> int:
left = 0 # Start at the leftmost line
right = len(height) - 1 # Start at the rightmost line
max_water = 0
while left < right:
# Width is the gap between pointers
# Height is capped by the shorter line
water = min(height[left], height[right]) * (right - left)
max_water = max(max_water, water)
# Move the shorter line inward — only move that can improve area
if height[left] < height[right]:
left += 1
else:
right -= 1 # Also handles equal heights — move either side
return max_water
Point out the equal height case — when both lines are the same height, moving either pointer is fine. The code handles this by moving right in the else branch.
Visual Walkthrough
Tracing through height = [1, 8, 6, 2, 5, 4, 8, 3, 7]:
Key steps of the pointer trace:
| L | R | h[L] | h[R] | Width | Area | Move |
|---|---|---|---|---|---|---|
| 0 | 8 | 1 | 7 | 8 | 8 | L left (h=1 shorter) |
| 1 | 8 | 8 | 7 | 7 | 49 ★ | R right (h=7 shorter) |
| 1 | 7 | 8 | 3 | 6 | 18 | R right (h=3 shorter) |
| 1 | 6 | 8 | 8 | 5 | 40 | R right (equal) |
| 1 | 5 | 8 | 4 | 4 | 16 | R right (h=4 shorter) |
| 1 | 4 | 8 | 5 | 3 | 15 | R right (h=5 shorter) |
| 1 | 3 | 8 | 2 | 2 | 4 | R right (h=2 shorter) |
| 1 | 2 | 8 | 6 | 1 | 6 | R right (h=6 shorter) |
| L=1, R=1 → left < right is false → stop | ||||||
Step 5: Highlight Edge Cases
"Ifheight = [1, 1], we compute area once:min(1,1) × 1 = 1, then the loop ends sinceleftandrightmeet. Correct."
"When both lines are equal height, moving either pointer is valid — we can't do better by keeping this pair since width can only shrink. Theelsebranch movesright— this is fine."
"e.g.[5, 5, 5, 5]— max area is the full width:5 × 3 = 15. The first computation captures this, and subsequent steps only decrease the width.max_watercorrectly retains the first (largest) value."
"A line of height 0 contributes nothing — min(0, x) = 0 for any x. The pointer on the zero-height line will immediately move inward. Handled correctly without special casing."
Step 6: State Time and Space Complexity
| Approach | Time | Space |
|---|---|---|
| Brute Force | O(n²) | O(1) |
| Two Pointers ✓ | O(n) | O(1) |
"Each pointer moves inward at mostntimes total — they never backtrack. So the while loop runs at mostniterations. Time is O(n), space is O(1) — just two index variables."
Interview Checklist for Container With Most Water
- Restate — "find two lines maximising area = min(heights) × width"
- State the area formula clearly —
min(h[L], h[R]) × (R - L) - Mention brute force O(n²) and dismiss it
- State the key insight — start widest, greedily move the shorter pointer inward
- Justify the greedy decision — moving the taller line can never improve the area
- Handle equal heights — moving either side is valid, explain why
- Handle zero height and two-element edge cases
- State O(n) time and O(1) space
- Ask before coding, don't just dive in
Related Problems to Practice
If you can solve Container With Most Water cleanly, try these next:
