You are given an array representing the elevation profile of a terrain, where each element corresponds to a vertical bar of width 1 positioned consecutively. After rainfall, water will accumulate in the valleys between these bars.
Your task is to calculate the total volume of water that can be trapped between the bars. Water at any position is bounded by the tallest bar to its left and the tallest bar to its right. The water level at a position equals the minimum of these two bounding heights, minus the bar's own height at that position.
Example 1:
` Input: heights = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1] Output: 6 Explanation: The bars form multiple valleys. Water accumulates as follows:
Example 2:
` Input: heights = [4, 2, 0, 3, 2, 5] Output: 9 Explanation: A large valley forms between the first bar (height 4) and last bar (height 5).
Example 3:
Input: heights = [3, 0, 2] Output: 2 Explanation: Water fills the valley at index 1 up to height 2.
Hint 1: Think About Water Level For each position, the water level is determined by the minimum of the maximum heights to its left and right. The trapped water at that position is this water level minus the bar's height (if positive).
Hint 2: Pre-compute Boundaries Consider pre-computing the maximum height to the left and right of each position. This allows you to calculate trapped water in a single pass through the array.
Hint 3: Two-Pointer Optimization You can solve this problem with O(1) extra space using two pointers starting from both ends. Move the pointer with the smaller maximum height inward while accumulating water based on the current maximum at that side.
Full Solution `` Approach Explanation:
The two-pointer solution works by maintaining two pointers at the start and end of the array, along with the maximum heights seen from each side.
Key Insight: At any moment, if
heights[left] < heights[right], we know that the water trapped at positionleftis determined solely byleft_max(notright_max), because there exists a taller bar on the right (at leastheights[right]).Algorithm Steps:
- Initialize two pointers at array boundaries and track maximum heights from each side
- Always process the pointer with the smaller current height
- If current height exceeds the respective max, update the max (no water trapped)
- Otherwise, add the difference between max and current height to total water
- Move the processed pointer inward and repeat
Time Complexity: O(n) - We visit each element exactly once
Space Complexity: O(1) - Only a constant number of variables used
Alternative Approach (Dynamic Programming):
You could also solve this using two auxiliary arrays to pre-compute
left_max[i]andright_max[i]for each position, then calculate water in a final pass. This uses O(n) space but is conceptually simpler.` def trapWaterDP(heights): """Alternative O(n) space solution using pre-computed arrays.""" if not heights: return 0
n = len(heights) left_max = [0] * n right_max = [0] * n # Fill left_max array left_max[0] = heights[0] for i in range(1, n): left_max[i] = max(left_max[i-1], heights[i]) # Fill right_max array right_max[n-1] = heights[n-1] for i in range(n-2, -1, -1): right_max[i] = max(right_max[i+1], heights[i]) # Calculate trapped water total_water = 0 for i in range(n): water_level = min(left_max[i], right_max[i]) total_water += max(0, water_level - heights[i]) return total_water`
def trapWater(heights):
"""
Calculate total water trapped using two-pointer approach.
Time Complexity: O(n) - single pass through array
Space Complexity: O(1) - only constant extra space
"""
if not heights or len(heights) < 3:
return 0
left = 0
right = len(heights) - 1
left_max = 0
right_max = 0
total_water = 0
# Move pointers inward, always processing the side with smaller max
while left < right:
if heights[left] < heights[right]:
# Process left side
if heights[left] >= left_max:
# Update left boundary
left_max = heights[left]
else:
# Water can be trapped here
total_water += left_max - heights[left]
left += 1
else:
# Process right side
if heights[right] >= right_max:
# Update right boundary
right_max = heights[right]
else:
# Water can be trapped here
total_water += right_max - heights[right]
right -= 1
return total_water