feat(content): test cases batch 2

This commit is contained in:
2025-05-24 21:00:16 +01:00
parent 1e4aafaff2
commit e8898841cf
10 changed files with 962 additions and 474 deletions

View File

@@ -12,68 +12,102 @@ patterns:
- 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.
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
- `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."
explanation: "The elevation map traps 6 units of water between the bars."
- input: "height = [4,2,0,3,2,5]"
output: "9"
explanation: "9 units of water are trapped."
explanation: "Water fills the valleys: 2 + 4 + 1 + 2 = 9 units."
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.
Visualise the elevation map as a cross-section of terrain. After rain, water fills the valleys but can't rise above the surrounding walls.
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.
Think of it like this: at any position `i`, the water level is determined by the **shorter** of the two walls — the tallest bar to the left and the tallest bar to the right. Water can't rise higher than this "limiting wall" without spilling over.
For position `i`:
- `left_max` = maximum height to the left of i
- `right_max` = maximum height to the right of i
- Water level at i = `min(left_max, right_max)`
- Water trapped at i = `water_level - height[i]` (if positive)
The clever insight for the two-pointer approach: if we know `left_max < right_max`, the water at the left position is limited by `left_max` — we don't need to know the exact `right_max`, just that it's bigger. This lets us process from both ends simultaneously.
approach: |
We solve this using **Two Pointers**:
**Step 1: Initialise pointers and tracking variables**
- `left = 0`, `right = n - 1` (start at both ends)
- `left_max = 0`, `right_max = 0` (maximum heights seen so far)
- `water = 0` (total water trapped)
&nbsp;
**Step 2: Process from both ends**
- While `left < right`:
- If `height[left] < height[right]`:
- If `height[left] >= left_max`: update `left_max`
- Else: water trapped = `left_max - height[left]`, add to total
- Move `left` right
- Else:
- If `height[right] >= right_max`: update `right_max`
- Else: water trapped = `right_max - height[right]`, add to total
- Move `right` left
&nbsp;
**Step 3: Return total water**
- After pointers meet, all positions have been processed
&nbsp;
Why process the shorter side? If `height[left] < height[right]`, the water at `left` is bounded by `left_max` (the right side is guaranteed to be at least as tall as `height[right]`, which is bigger). We can safely compute water at `left` without knowing the exact `right_max`.
common_pitfalls:
- title: Only considering one side
- title: Only Considering One Side
description: |
Water level is determined by BOTH sides. You need to track maximum from left AND right.
Water level at any position depends on BOTH the left maximum and right maximum. If you only track one side, you'll compute incorrect water levels.
The two-pointer approach cleverly tracks both sides by processing the limiting side first.
wrong_approach: "Only tracking left_max"
correct_approach: "Track both left_max and right_max"
- title: Counting bars instead of water
- title: Counting Bar Height as Water
description: |
Water trapped at position i is max_height - height[i], not max_height.
The bar itself takes up space.
Water trapped at position i is `max_height - height[i]`, not just `max_height`. The bar itself occupies space and can't hold water.
wrong_approach: "water += left_max"
correct_approach: "water += left_max - height[left]"
- title: Not updating max heights
- title: Not Updating Max Before Computing Water
description: |
Update left_max or right_max before calculating water, not after.
Update `left_max` or `right_max` **before** computing water. If the current bar is taller than the previous max, no water is trapped there (it's a new "wall").
The code should check: if current >= max, update max; else compute water.
wrong_approach: "Computing water, then updating max"
correct_approach: "if height >= max: max = height; else: water += max - height"
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
- "**Water level = min(left_max, right_max)**: The shorter wall determines the water level"
- "**Two pointers eliminate precomputation**: No need to precompute left_max and right_max arrays"
- "**Process the limiting side**: If left is shorter, it's bounded by left_max; process it and move inward"
- "**Multiple approaches exist**: DP (precompute arrays), monotonic stack, and two pointers all work"
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.
time_complexity: "O(n). Single pass with two pointers, processing each position once."
space_complexity: "O(1). Only a few variables for pointers and maximum values."
solutions:
- approach_name: Two Pointers (Optimal)
- approach_name: Two Pointers
is_optimal: true
code: |
def trap(height: list[int]) -> int:
@@ -86,12 +120,16 @@ solutions:
while left < right:
if height[left] < height[right]:
# Left side is the limiting factor
if height[left] >= left_max:
# New wall — update max, no water here
left_max = height[left]
else:
# Valley — water trapped up to left_max
water += left_max - height[left]
left += 1
else:
# Right side is the limiting factor
if height[right] >= right_max:
right_max = height[right]
else:
@@ -100,30 +138,38 @@ solutions:
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.
**Time Complexity:** O(n) — Single pass through the array.
**Space Complexity:** O(1) — Only constant extra space.
We process from both ends, always moving the pointer on the shorter side. If the current height exceeds the running max, it becomes the new max (a wall). Otherwise, water is trapped equal to the difference between max and current height. The key insight: processing the shorter side first guarantees correct water calculation.
- approach_name: Monotonic Stack
is_optimal: false
code: |
def trap(height: list[int]) -> int:
stack = [] # stores indices
stack = [] # Stores indices of bars in decreasing height
water = 0
for i, h in enumerate(height):
# Pop shorter bars and calculate water in the valley
while stack and h > height[stack[-1]]:
top = stack.pop()
bottom = stack.pop()
if not stack:
break
break # No left boundary
# Calculate water in this layer
width = i - stack[-1] - 1
bounded_height = min(h, height[stack[-1]]) - height[top]
bounded_height = min(h, height[stack[-1]]) - height[bottom]
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".
**Time Complexity:** O(n) — Each index pushed and popped at most once.
**Space Complexity:** O(n) — Stack can hold up to n indices.
The stack maintains bars in decreasing order. When we encounter a taller bar, we pop shorter bars and calculate water trapped in the "valley" between the current bar and the previous taller bar on the stack. Water is computed layer by layer, horizontally.