LeetCode 11 — Container With Most Water | Full Solution Explained

DifficultyPatternAsked AtLeetCode Link
MediumTwo Pointers (Opposite Ends)Amazon, Google, Microsoft, Bloomberg, Appleleetcode.com/problems/container-with-most-water
📌  This is part of the Two Pointers series on Daily Dev Notes. If you haven’t read the Two Pointers pattern guide yet, start there — it will make this solution much easier to understand.

This problem has a sneaky quality to it.

When you first read it, it looks like a geometry problem. But once you see the right way to think about it, it becomes a clean, elegant Two Pointers problem that solves in a single pass.

The hard part is not the code — the code is just 10 lines. The hard part is building the intuition for why the Two Pointers approach is correct. That’s what this post focuses on.

Let’s go from scratch.

The 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 i-th line are at (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.

Note: You cannot slant the container.

Example

Example 1:
  Input:  height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
  Output: 49
  Why:    Lines at index 1 (height=8) and index 8 (height=7)
          Width  = 8 - 1 = 7
          Height = min(8, 7) = 7
          Area   = 7 × 7 = 49
 
Example 2:
  Input:  height = [1, 1]
  Output: 1
  Why:    Only two lines. Width=1, Height=min(1,1)=1, Area=1

Understanding the Area Formula

Before jumping into the solution, let’s make sure the area calculation is completely clear.

If you pick two lines at positions i and j (where i < j), the water they can hold is:

Example

Area = width × height
     = (j - i) × min(height[i], height[j])
 
The height is min() of the two lines because water spills
over the shorter one — you can never fill above the shorter line.
💡  The area is always limited by the SHORTER line. This single observation is the entire key to understanding why the Two Pointers approach works.

Step 1 — Brute Force Approach

As always, let’s start with the obvious solution. Check every possible pair of lines and track the maximum area.

Brute Force

// Brute Force — O(n²) time, O(1) space
int maxArea(vector<int>& height) {
    int maxWater = 0;
    int n = height.size();
 
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int width  = j - i;
            int h      = min(height[i], height[j]);
            int area   = width * h;
            maxWater   = max(maxWater, area);
        }
    }
    return maxWater;
}
MetricBrute ForceImpact
Time ComplexityO(n²)Two nested loops — for n=10,000, that’s 100 million operations
Space ComplexityO(1)Fine — no extra data structures
LeetCode ResultTLEFails on large test cases — Time Limit Exceeded
⚠️  The brute force is logically correct but too slow. For n = 100,000 lines, it would need 10 billion comparisons. We need O(n).

Step 2 — Building the Intuition

This is the most important section. Read it slowly.

Let’s start with two pointers — one at the leftmost line (index 0) and one at the rightmost line (index n-1). This gives us the maximum possible width.

Now we calculate the area. Then we ask: should we move the left pointer or the right pointer?

🤔  Here is the key question: if we move one pointer inward, the WIDTH always decreases. So for the area to possibly increase, the HEIGHT must increase. Which pointer should we move to give the HEIGHT a chance to increase?

The Proof — Why We Always Move the Shorter Line

Say the left line has height 3 and the right line has height 8. The current area is limited by height 3 (the shorter one).

What if we move the RIGHT pointer (height 8) inward? 
Width decreasesAlways — we moved inward
New right line heightCould be anything — but the area is STILL limited by left line (height 3)
Can area increase?NO — width went down, height is still capped at 3. Area can only stay same or decrease.
What if we move the LEFT pointer (height 3) inward? 
Width decreasesAlways — we moved inward
New left line heightCould be greater than 3 — this is our only chance for area to increase
Can area increase?YES — if the new left height is greater than 3, the effective height increases and might outweigh the width decrease
🔑  CONCLUSION: Always move the pointer pointing to the SHORTER line. Moving the taller line’s pointer can never increase the area. Moving the shorter line’s pointer is the only move that gives us a chance at a larger area.

This is the entire algorithm. Everything else — the code, the loop — is just implementing this one insight.

Step 3 — Full Dry Run

Let’s trace through Example 1 completely.

Dry Run

height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
index   = [0, 1, 2, 3, 4, 5, 6, 7, 8]
maxArea = 0
Stepleftrighth[left]h[right]WidthHeightAreamaxAreaMove
108178188left++ (1 < 7)
21887774949right– (8 > 7)
31783631849right– (8 > 3)
41688584049right– (tie → move right)
51584441649right– (8 > 4)
61485351549right– (8 > 5)
7138222449right– (8 > 2)
8128616649right– (8 > 6)
91149left >= right → STOP
✅  Maximum area = 49. Found at Step 2: lines at index 1 (height=8) and index 8 (height=7). Width=7, Height=7, Area=49.

Notice something important in Step 4: when both lines have the same height (both are 8), we can move either pointer — it doesn’t matter. Moving either one cannot increase the area since height stays capped at 8 and width decreases.

Step 4 — The Optimal Solution

Now the code. After all that intuition-building, the solution is surprisingly clean.

C++ Solution

#include <vector>
#include <algorithm>
using namespace std;
 
class Solution {
public:
    int maxArea(vector<int>& height) {
        int left    = 0;                   // start at leftmost line
        int right   = height.size() - 1;  // start at rightmost line
        int maxWater = 0;                  // track maximum area seen
 
        while (left < right) {
            // calculate current container area
            int width  = right - left;
            int h      = min(height[left], height[right]);
            int area   = width * h;
 
            // update maximum if current area is larger
            maxWater = max(maxWater, area);
 
            // move the pointer at the SHORTER line inward
            // (moving the taller line can never increase area)
            if (height[left] < height[right]) {
                left++;   // left is shorter — move it right
            } else {
                right--;  // right is shorter (or equal) — move it left
            }
        }
 
        return maxWater;
    }
};

Python Solution

class Solution:
    def maxArea(self, height: list[int]) -> int:
        left     = 0                  # start at leftmost line
        right    = len(height) - 1   # start at rightmost line
        max_water = 0                 # track maximum area seen
 
        while left < right:
            # calculate current container area
            width = right - left
            h     = min(height[left], height[right])
            area  = width * h
 
            # update maximum if current area is larger
            max_water = max(max_water, area)
 
            # move the pointer at the SHORTER line inward
            if height[left] < height[right]:
                left += 1    # left is shorter — move it right
            else:
                right -= 1   # right is shorter (or equal) — move it left
 
        return max_water

JavaScript Solution

/**
 * @param {number[]} height
 * @return {number}
 */
var maxArea = function(height) {
    let left     = 0;                 // start at leftmost line
    let right    = height.length - 1; // start at rightmost line
    let maxWater = 0;                 // track maximum area seen
 
    while (left < right) {
        // calculate current container area
        const width = right - left;
        const h     = Math.min(height[left], height[right]);
        const area  = width * h;
 
        // update maximum if current area is larger
        maxWater = Math.max(maxWater, area);
 
        // move the pointer at the SHORTER line inward
        if (height[left] < height[right]) {
            left++;    // left is shorter — move it right
        } else {
            right--;   // right is shorter (or equal) — move it left
        }
    }
 
    return maxWater;
};

Step 5 — Complexity Analysis

MetricBrute ForceTwo PointersExplanation
TimeO(n²)O(n)left only moves right, right only moves left — n total moves max
SpaceO(1)O(1)Only 4 integer variables — left, right, maxWater, area
🚀  O(n) time and O(1) space. For n = 100,000 lines, Two Pointers makes 100,000 moves. Brute force makes 10 billion. That’s the difference between 0.1ms and 100 seconds.

Why It’s O(n) — Step by Step Reasoning

  • left starts at 0 and only ever increases
  • right starts at n-1 and only ever decreases
  • Each iteration moves exactly one pointer by exactly one step
  • The loop stops when left >= right
  • Total iterations = at most n-1 (they can never cross)
  • Each iteration does O(1) work — one subtraction, one min, one multiply, one compare
  • Total: O(n) time

Step 6 — Common Wrong Approaches and Why They Fail

Wrong Approach 1 — Always Move Both Pointers

Some people think: ‘just move both pointers inward every step’. This is wrong because you will skip valid pairs. The answer might require moving only left for several steps in a row.

⚠️  Never move both pointers at the same time. Decide which one to move based on which line is shorter — and move only that one.

Wrong Approach 2 — Move the Taller Line’s Pointer

This is the most common mistake. Someone thinks: ‘the taller line contributes more to height, so keep it and move the shorter one… wait, or is it the other way?’

Remember the proof from Step 2: moving the taller line’s pointer can NEVER increase the area. The area is capped by the shorter line, and width is decreasing. So area can only decrease or stay the same.

🔑  Move the SHORTER line’s pointer. Always. The proof is: moving the taller pointer gives no chance of gain. Moving the shorter pointer is the only move with upside potential.

Wrong Approach 3 — Greedy Starting from the Tallest Bar

Some people try to find the tallest bar first and expand from there. This does not work because the optimal container might not involve the tallest bar at all. The area depends on both height AND width — a wide container with medium-height bars can beat a narrow container with tall bars.

Step 7 — Edge Cases

Edge CaseInputExpected OutputHandled?
Only 2 lines[1, 1]1Yes — one iteration, left=0, right=1, area=1
All same height[5, 5, 5, 5]15Yes — width=3, height=5, area=15
Decreasing heights[6, 5, 4, 3]9Yes — left stays at 0, right moves left each time
One very tall middle bar[1, 100, 1]2Yes — best is left+right = width 2, height 1 = 2
Answer at first step[8, 1, 1, 8]24Yes — first step catches it, maxWater=24
✅  Our Two Pointers solution handles all edge cases correctly without any special case logic.

Step 8 — How to Explain This in a Real Interview

Container With Most Water is a favourite at Amazon, Google, and Microsoft. Here is exactly how to walk through it:

  • Step 1 — Restate the problem: ‘I need to find two lines that maximise width times the shorter height.’
  • Step 2 — Brute force: ‘I can check all O(n²) pairs but that’s too slow. I need O(n).’
  • Step 3 — Intuition: ‘Since the area is limited by the shorter line, if I move the taller line’s pointer inward, width decreases and height can only stay the same or decrease — so area can never increase. Therefore I should always move the shorter line’s pointer.’
  • Step 4 — Algorithm: ‘Start with pointers at both ends for maximum width. Move shorter pointer inward each step. Track maximum area seen.’
  • Step 5 — Code: Write the clean 15-line solution.
  • Step 6 — Complexity: ‘O(n) time, O(1) space — each pointer moves at most n times.’
  • Step 7 — Edge cases: Mention arrays of size 2, all equal heights, answer at first step.
💡  The interviewer wants to see that you can PROVE why the greedy choice (moving the shorter pointer) is correct. That proof — not the code — is what separates a good answer from a great answer.

This Problem vs Two Sum II — What’s Different?

FeatureTwo Sum II (LC 167)Container With Most Water (LC 11)
GoalFind pair summing to targetFind pair maximising area
Stop conditionStop when sum == targetNever stop early — must check all possible pairs
Move decisionBased on sum vs targetAlways move shorter pointer
Sorted input?Yes — requiredNo — works on any array
OutputIndices of the pairMaximum area value
📌  A key difference: in Two Sum II we stop as soon as we find the answer. In Container With Most Water we NEVER stop early — we always run until left >= right because the maximum might be found at any step.

Final Solution at a Glance

int maxArea(vector<int>& height) {
    int left = 0, right = height.size() - 1, maxWater = 0;
 
    while (left < right) {
        int area = (right - left) * min(height[left], height[right]);
        maxWater = max(maxWater, area);
 
        if (height[left] < height[right]) left++;
        else right--;
    }
 
    return maxWater;
}
Time ComplexitySpace ComplexityLeetCode ResultDifficulty
O(n)O(1)Accepted ✓Medium

Wrapping Up

Container With Most Water is one of those problems where the ‘aha’ moment hits hard. Once you understand that the area is always limited by the shorter line — and that moving the taller line’s pointer is therefore always a waste — the Two Pointers solution becomes obvious.

The three things to remember from this problem:

  • Area = width × min(height[left], height[right])
  • Always move the pointer at the SHORTER line inward
  • Never stop early — always run until left >= right

These three rules, plus the proof of why they work, are what you need to nail this in any interview.

📬  This is part of the Two Pointers series on Daily Dev Notes. Next up: LeetCode 15 — 3Sum. Subscribe to the newsletter so you don’t miss it.

What is the time and space complexity of LeetCode 11 Container With Most Water?

What is the time and space complexity of LeetCode 11 Container With Most Water?

Why does moving the shorter line’s pointer give the optimal solution in Container With Most Water?

The area is always limited by the shorter line. If we move the taller line’s pointer inward, the width decreases AND the height can only stay the same or decrease — so the area can never increase. Moving the shorter line’s pointer is the only move that can possibly give a larger area.

What pattern is used to solve LeetCode 11?

LeetCode 11 is solved using the Two Pointers (Opposite Ends) pattern. One pointer starts at the left end and one at the right end. They move inward based on which line is shorter, tracking the maximum area seen so far.

Have a question about any step in this post? Drop it in the comments — I reply to every one.

Leave a Comment