๐ This problem is a classic application of the Two-Pointer technique. It challenges us to find the maximum volume a container can hold, given varying heights of vertical lines.
๐งฉ The core insight is realizing that the volume is limited by the shorter of the two lines. By starting from the widest possible container and strategically moving our pointers inward, we can find the optimal solution in linear time.
๐ We use a greedy approach: always move the pointer pointing to the shorter line, as this is the only way we might find a taller line that compensates for the decreased width.
๐ The Problem
You are given an integer array
heightof lengthn. There arenvertical lines drawn such that the two endpoints of the line are(i, 0)and(i, height[i]).Find two lines that together with the x-axis form a container, such that the container contains the most water.
Return the maximum amount of water a container can store.
Example:
- Input:
height = [1,8,6,2,5,4,8,3,7] - Output:
49 - Explanation: The max area is formed between index 1 (height 8) and index 8 (height 7). Width = . Height = . Area = .
๐ ๏ธ Approach: Two Pointers (Greedy)
The brute force approach would be to check every possible pair of lines, which takes time. However, we can do better!
- Initialize Pointers: Start with one pointer at the beginning (
left = 0) and one at the end (right = len(height) - 1). - Calculate Area: At each step, calculate the area:
min(height[left], height[right]) * (right - left). - Update Max Area: Keep track of the maximum area seen so far.
- Move Pointers Greedily:
- If
height[left] < height[right], incrementleft. - Otherwise, decrement
right. - Why? Because the width is decreasing. To potentially increase the area, we must find a taller line. Moving the shorter line is our only hope for a larger height that might offset the smaller width.
- If
๐ Visualizing the Approach (Dry Run)
Input: height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
| Step | Left (i) | Right (j) | Height[L] | Height[R] | Width | Current Area | Max Area | Move |
|---|---|---|---|---|---|---|---|---|
| 1 | 0 (val: 1) | 8 (val: 7) | 1 | 7 | 8 | 1 ร 8 = 8 | 8 | L++ |
| 2 | 1 (val: 8) | 8 (val: 7) | 8 | 7 | 7 | 7 ร 7 = 49 | 49 | R-- |
| 3 | 1 (val: 8) | 7 (val: 3) | 8 | 3 | 6 | 3 ร 6 = 18 | 49 | R-- |
| 4 | 1 (val: 8) | 6 (val: 8) | 8 | 8 | 5 | 8 ร 5 = 40 | 49 | R-- |
| 5 | 1 (val: 8) | 5 (val: 4) | 8 | 4 | 4 | 4 ร 4 = 16 | 49 | R-- |
| 6 | 1 (val: 8) | 4 (val: 5) | 8 | 5 | 3 | 5 ร 3 = 15 | 49 | R-- |
| 7 | 1 (val: 8) | 3 (val: 2) | 8 | 2 | 2 | 2 ร 2 = 4 | 49 | R-- |
| 8 | 1 (val: 8) | 2 (val: 6) | 8 | 6 | 1 | 6 ร 1 = 6 | 49 | R-- |
๐ป Implementation
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
left = 0
right = len(height) - 1
max_area = 0
while left < right:
# Calculate area based on shorter line
if height[left] < height[right]:
h = height[left]
area = h * (right - left)
left += 1
else:
h = height[right]
area = h * (right - left)
right -= 1
# Update maximum area
if area > max_area:
max_area = area
return max_areaโฑ๏ธ Complexity Analysis
| Complexity | Rating | Description |
|---|---|---|
| Time Complexity | ๐ Optimal. We traverse the array once. | |
| Space Complexity | ๐ Optimal. Only constant extra space used. |
๐ง How to Recognize This Pattern
- Array/Sequence Input: The problem involves picking a pair of elements.
- Constraint-Based Optimization: You need a "max" or "min" value that depends on the distance between two indices.
- Shrinking Range: If checking the outermost elements provides a "starting bound" and moving inward can only improve the quality at the cost of range, Two-Pointer is likely.
Similar Problems:
- Two Sum (Sorted)
- Trapping Rain Water
- 3Sum
๐ฏ Interview Tips
- Explain the Greedy Choice: Explicitly state that moving the taller pointer is useless because the area is limited by the shorter one, and the width is already shrinking.
- The Proof: If an interviewer asks for a proof, you can mention that we never skip the optimal solution because at any point, the optimal solution must either have our current pointers or be "inside" them.
- Clean Code: Notice how we update
max_areaafter moving the pointers (or calculate it before). Both are fine as long as you are consistent.
# Performance Stats
# Runtime: 45 ms (Beats 98.13%)
# Memory: 20.61 MB (Beats 63.35%)