130 lines
4.1 KiB
YAML
130 lines
4.1 KiB
YAML
title: Trapping Rain Water
|
|
slug: trapping-rain-water
|
|
difficulty: hard
|
|
leetcode_id: 42
|
|
leetcode_url: https://leetcode.com/problems/trapping-rain-water/
|
|
categories:
|
|
- arrays
|
|
- two-pointers
|
|
- stack
|
|
patterns:
|
|
- two-pointers
|
|
- monotonic-stack
|
|
|
|
description: |
|
|
Given n non-negative integers representing an elevation map where the width of each bar is 1,
|
|
compute how much water it can trap after raining.
|
|
|
|
constraints: |
|
|
- n == height.length
|
|
- 1 <= n <= 2 * 10^4
|
|
- 0 <= height[i] <= 10^5
|
|
|
|
examples:
|
|
- input: "height = [0,1,0,2,1,0,1,3,2,1,2,1]"
|
|
output: "6"
|
|
explanation: "6 units of water are trapped between the bars."
|
|
- input: "height = [4,2,0,3,2,5]"
|
|
output: "9"
|
|
explanation: "9 units of water are trapped."
|
|
|
|
explanation:
|
|
approach: |
|
|
1. Use two pointers from left and right
|
|
2. Track maximum height seen from each side
|
|
3. Move the pointer with smaller max height
|
|
4. Water at current position = max_height - current_height
|
|
5. Add to total and continue until pointers meet
|
|
|
|
intuition: |
|
|
Water at any position is determined by the minimum of the maximum heights to its left
|
|
and right, minus the current height.
|
|
|
|
With two pointers, we track left_max and right_max. If left_max < right_max, water at
|
|
the left pointer is limited by left_max (the right side is guaranteed to be at least
|
|
as tall). We process and move the pointer with the smaller maximum.
|
|
|
|
common_pitfalls:
|
|
- title: Only considering one side
|
|
description: |
|
|
Water level is determined by BOTH sides. You need to track maximum from left AND right.
|
|
wrong_approach: "Only tracking left_max"
|
|
correct_approach: "Track both left_max and right_max"
|
|
|
|
- title: Counting bars instead of water
|
|
description: |
|
|
Water trapped at position i is max_height - height[i], not max_height.
|
|
The bar itself takes up space.
|
|
|
|
- title: Not updating max heights
|
|
description: |
|
|
Update left_max or right_max before calculating water, not after.
|
|
|
|
key_takeaways:
|
|
- Two pointers eliminate need for O(n) precomputation
|
|
- Water level = min(left_max, right_max) - current_height
|
|
- Always process the side with smaller max (guaranteed bound)
|
|
- This can also be solved with monotonic stack or DP
|
|
|
|
time_complexity: "O(n)"
|
|
space_complexity: "O(1)"
|
|
complexity_explanation: |
|
|
Time: Single pass with two pointers.
|
|
Space: Only a few variables for pointers and max values.
|
|
|
|
solutions:
|
|
- approach_name: Two Pointers (Optimal)
|
|
is_optimal: true
|
|
code: |
|
|
def trap(height: list[int]) -> int:
|
|
if not height:
|
|
return 0
|
|
|
|
left, right = 0, len(height) - 1
|
|
left_max, right_max = 0, 0
|
|
water = 0
|
|
|
|
while left < right:
|
|
if height[left] < height[right]:
|
|
if height[left] >= left_max:
|
|
left_max = height[left]
|
|
else:
|
|
water += left_max - height[left]
|
|
left += 1
|
|
else:
|
|
if height[right] >= right_max:
|
|
right_max = height[right]
|
|
else:
|
|
water += right_max - height[right]
|
|
right -= 1
|
|
|
|
return water
|
|
explanation: |
|
|
Process from both ends. Move the pointer with smaller max height.
|
|
Add water based on the difference between max height and current height.
|
|
|
|
- approach_name: Monotonic Stack
|
|
is_optimal: false
|
|
code: |
|
|
def trap(height: list[int]) -> int:
|
|
stack = [] # stores indices
|
|
water = 0
|
|
|
|
for i, h in enumerate(height):
|
|
while stack and h > height[stack[-1]]:
|
|
top = stack.pop()
|
|
|
|
if not stack:
|
|
break
|
|
|
|
width = i - stack[-1] - 1
|
|
bounded_height = min(h, height[stack[-1]]) - height[top]
|
|
water += width * bounded_height
|
|
|
|
stack.append(i)
|
|
|
|
return water
|
|
explanation: |
|
|
Stack stores indices of bars in decreasing height order.
|
|
When a taller bar is found, calculate water trapped in the "valley".
|