Skip to content

Practice problem

Widest Water Tank

Medium

Solve in Python · graded against 2 sample tests and a hidden test set in your browser · Published

Interactive solution

Solve Widest Water Tank

Run tries the first sample. Submit checks every sample and additional cases. Your code is saved in this browser.

Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

Problem Statement

You're given the heights of a row of vertical support beams, evenly spaced one unit apart. You want to pick exactly two of these beams to serve as the two walls of a rectangular water tank; the ground between them is the floor, and the water can rise no higher than the shorter of the two chosen beams (any higher and it would simply spill over that side). The tank's capacity is therefore the shorter beam's height times the distance between the two beams. Find the maximum capacity achievable by any choice of two beams.

Input Format

The input is exactly one line: the beam heights, as space-separated non-negative integers, from left to right. There are at least 2 heights.

Output Format

Print a single integer: the maximum capacity, min(heights[i], heights[j]) * (j - i), over every pair of positions i < j.

Example Walkthrough

Take the second sample, 7 7. There's only one possible pair here — the beam at position 0 and the beam at position 1 — so the answer has to come from that single pair: min(7, 7) * (1 - 0) = 7.

Now consider a two-pointer trace on the first sample, 6 2 9 4 1 8 3 7 2 (positions 0-8). Start with left = 0 (height 6) and right = 8 (height 2). The capacity between them is min(6, 2) * 8 = 16, so the best so far is 16. Height 2 is the shorter of the two, so move right inward to position 7 (height 7). Now the capacity is min(6, 7) * 7 = 42, which beats the previous best, so the best becomes 42. This time height 6 (at left) is the shorter one, so move left inward instead, to position 1 (height 2): min(2, 7) * 6 = 12, no improvement, and left moves again to position 2 (height 9). Now min(9, 7) * 5 = 35 — still short of 42, and since 7 is the shorter wall, right starts walking inward: position 6 (height 3) gives 3 * 4 = 12, position 5 (height 8) gives min(9, 8) * 3 = 24, position 4 (height 1) gives 1 * 2 = 2, and position 3 (height 4) gives 4 * 1 = 4. The pointers then meet, and the best capacity recorded is 42, matching the expected output. Notice that the tallest beam, the 9, never produced the answer: by the time a pointer reached it, the width had already shrunk too far.

Approach

Checking every pair of beams directly works, but it's O(n²): for each of the n beams, you'd compare it against up to n-1 others. That's wasteful for a large row of beams.

The two-pointer approach starts from the widest possible pair — the leftmost and rightmost beams — and narrows in from there, doing only O(n) work total. At each step, compute the capacity for the current pair and update the best seen so far. Then move the pointer that's on the shorter of the two beams one step inward (moving either pointer when they're equal). The reasoning behind always moving the shorter one is what makes this correct: keeping the current pair's width and instead moving the taller beam's pointer inward could only ever shrink the width while the water level stays capped by the same beam (the shorter one didn't move) — that can never produce more water than the current pair already did. So there's no need to ever check that option; the only way to possibly do better is to move the shorter beam's pointer inward, hoping to find a taller replacement, even though the width shrinks by one either way.

Because each step moves one of the two pointers strictly inward and they start n-1 apart, the pointers meet after at most n-1 steps, giving O(n) time using only a constant amount of extra memory.

Common Mistakes

  • Moving the pointer at the taller beam instead of the shorter one. It's tempting to think you should "get rid of" whichever beam looks less promising, but the correct move is always to advance the pointer sitting on the shorter beam — moving the taller one's pointer can only ever make things worse or equal, never better, as explained above.
  • Recomputing the maximum with a nested loop "just to be safe." Once the two-pointer scan is written correctly, no second pass or extra checking is needed — adding a nested loop on top reintroduces the O(n²) cost the two-pointer technique was meant to avoid, for no benefit in correctness.
  • Forgetting that height 0 is a valid, meaningful height. A beam of height 0 can still be part of the widest pair by width, but any tank that uses it as one of its two walls holds exactly 0 water (since the water level is capped at 0) — that pair should still be considered when scanning, just correctly contributes 0 rather than being skipped over or treated as invalid input.

Constraints

  • The input line has at least 2 and at most 100,000 non-negative integers.
  • Each height is between 0 and 1,000,000,000, inclusive.
  • Heights may repeat, and any number of them may be 0.

Target complexity

Time: O(n) — the two pointers start at opposite ends and move toward each other, so together they take at most n steps before meeting.

Space: O(1) — only the two pointer positions and the best amount seen so far need to be tracked, regardless of how many beams there are.

Sample tests

Sample 1

Input

6 2 9 4 1 8 3 7 2

Expected output

42

Picking the beams at positions 0 and 7 (heights 6 and 7) gives width 7 and a water level capped by the shorter beam, 6, for 6 * 7 = 42 — the largest amount any pair of beams in this row can hold. The tallest beam, the 9 at position 2, never wins: it sits too close to every beam tall enough to match it.

Sample 2

Input

7 7

Expected output

7

There are only two beams to choose from, at width 1 apart with height 7 each, so the tank holds min(7, 7) * 1 = 7.

More problems

All practice problems →