-
Notifications
You must be signed in to change notification settings - Fork 273
The Widest Reservoir
TIP103 Unit 11 Session 1 (Click for link to problem statements)
A row of vertical walls has heights given by heights, where wall i stands at position i. Choosing two walls forms a container whose water capacity is the shorter wall's height times the distance between them.
Return the maximum amount of water any pair of walls can hold.
def max_area(heights):
pass- 💡 Difficulty: Medium
- ⏰ Time to complete: 20-30 mins
- 🛠️ Topics: Arrays, Two Pointers, Greedy
Understand what the interviewer is asking for by using test cases and questions about the problem.
- Established a set (2-3) of test cases to verify their own solution later.
- Established a set (1-2) of edge cases to verify their solution handles complexities.
- Have fully understood the problem and have no clarifying questions.
- Have you verified any Time/Space Constraints for this problem?
-
Q: How is the capacity of a pair of walls calculated?
- A: Capacity =
min(heights[i], heights[j]) * (j - i). The water level cannot rise above the shorter wall, and the width is the distance between the two positions.
- A: Capacity =
-
Q: Do the walls between the chosen pair affect the capacity?
- A: No. Only the two chosen walls matter; any walls between them are ignored (the water sits above them).
-
Q: Can the container be tilted, or can we use more than two walls?
- A: No. Exactly two walls are chosen, and the capacity formula above is the only rule.
HAPPY CASE
Input: heights = [1, 8, 6, 2, 5, 4, 8, 3, 7]
Output: 49
Explanation: Walls at positions 1 and 8 have heights 8 and 7. Capacity = min(8, 7) * (8 - 1) = 7 * 7 = 49, the maximum over all pairs.
EDGE CASE
Input: heights = [1, 1]
Output: 1
Explanation: Only one pair exists. Capacity = min(1, 1) * 1 = 1.
Input: heights = [1, 2, 1]
Output: 2
Explanation: The tallest wall alone holds nothing; the best pair is the two outer walls: min(1, 1) * 2 = 2.
Match what this problem looks like to known categories of problems, e.g. Linked List or Dynamic Programming, and strategies or patterns in those categories.
For Maximizing over Pairs in an Array, we can consider the following approaches:
- Two Pointers: Start with the widest possible container (leftmost and rightmost walls) and greedily shrink inward from the shorter side, since moving the taller wall inward can never increase the capacity.
-
Brute Force: Check every pair of walls in
O(N^2). Correct, but too slow for large inputs and a signal to look for the two-pointer optimization.
Plan the solution with appropriate visualizations and pseudocode.
General Idea:
Place one pointer at each end of the array so we begin with the maximum width. At each step, record the capacity of the current pair, then move the pointer at the shorter wall inward. Moving the shorter wall is the only move that can possibly find a larger capacity: the width always shrinks, so the only hope is a taller limiting wall. Repeat until the pointers meet, tracking the best capacity seen.
1) Initialize `left = 0`, `right = len(heights) - 1`, and `best = 0`.
2) While `left < right`:
a) Compute capacity = min(heights[left], heights[right]) * (right - left).
b) Update `best` if this capacity is larger.
c) If heights[left] < heights[right], move `left` inward by 1.
Otherwise, move `right` inward by 1.
3) Return `best`.
- Moving the pointer at the taller wall — the shorter wall is the bottleneck, so keeping it can never improve the capacity as the width shrinks.
- Using the taller wall's height (or the sum/average) in the capacity formula instead of the shorter wall's height.
- Returning the capacity of the first or last pair checked instead of tracking the maximum across all steps.
Implement the code to solve the algorithm.
def max_area(heights):
left, right = 0, len(heights) - 1
best = 0
while left < right:
# Capacity is limited by the shorter wall times the distance between walls
width = right - left
capacity = min(heights[left], heights[right]) * width
best = max(best, capacity)
# Move the pointer at the shorter wall inward; moving the taller
# one can never increase the capacity
if heights[left] < heights[right]:
left += 1
else:
right -= 1
return bestReview the code by running specific example(s) and recording values (watchlist) of your code's variables along the way.
-
Input: heights = [1, 8, 6, 2, 5, 4, 8, 3, 7]
-
left = 0 (h=1),right = 8 (h=7): capacity = 1 * 8 = 8, best = 8. Left wall is shorter, soleftmoves to 1. -
left = 1 (h=8),right = 8 (h=7): capacity = 7 * 7 = 49, best = 49. Right wall is shorter, sorightmoves to 7. - The pointers continue inward (capacities 18, 40, 16, 15, 4, 6) but nothing beats 49.
- Output: 49
-
-
Input: heights = [1, 1]
-
left = 0 (h=1),right = 1 (h=1): capacity = 1 * 1 = 1, best = 1. Pointers meet and the loop ends. - Output: 1
-
Evaluate the performance of your algorithm and state any strong/weak or future potential work.
Assume N is the number of walls in heights.
-
Time Complexity:
O(N)because each step moves one pointer inward, so the pointers together make at mostN - 1moves before meeting. -
Space Complexity:
O(1)because we only store the two pointers and the running maximum.