Minimum Number of Taps to Water Garden
Master this topic with zero to advance depth.
Minimum Number of Taps to Water Garden
There is a one-dimensional garden from 0 to n. There are n + 1 taps at points [0, 1, ..., n]. Tap i can water the area [i - ranges[i], i + ranges[i]].
Return the minimum number of taps to water the entire garden [0, n]. If impossible, return -1.
Visual Representation
n = 5, ranges = [3, 4, 1, 1, 0, 0]
Tap 0: [0, 3]
Tap 1: [0, 5] <--- Covers everything alone!
Tap 2: [1, 3]
...
Optimal: 1 (Tap 1)Examples
Tap at index 1 covers [0,5], which is the entire garden.
Level I: Brute Force (Recursive Backtracking)
Intuition
Try every subset of taps and check if they together cover the garden [0, n]. This can be implemented using recursion by deciding for each tap whether to include it or not.
Thought Process
solve(tapIdx, currentCoverage)- At each step, either take the current tap or skip it.
- Base case: If
tapIdx == n + 1, check ifcurrentCoverage >= n. - This approach is extremely slow due to combinations.
Detailed Dry Run
n=3, taps=[[0,2], [1,3]]
- solve(0, 0): Take [0,2] -> solve(1, 2) -> Take [1,3] -> solve(2, 3) -> SUCCESS (2 taps)
- solve(0, 0): Skip [0,2] -> solve(1, 0) -> Take [1,3] -> FAIL (Gap at [0,1])
Level II: Dynamic Programming
Intuition
Define dp[i] as the minimum number of taps needed to water the garden from index to . For each tap, we update all indices it covers.
Thought Process
- Initialize
dparray of sizen+1with a large value (infinity). dp[0] = 0(no taps needed to cover index 0).- For each tap
iwith range[left, right]:- For every
jsuch thatleft <= j <= right:dp[right] = min(dp[right], dp[j] + 1).
- For every
Pattern: Interval DP / Shortest Path in DAG
Detailed Dry Run
n=5, ranges=[3,4,1,1,0,0], dp=[0, inf, inf, inf, inf, inf]
- Tap 0: [0,3]. dp[1..3] = min(inf, dp[0]+1) = 1. dp=[0, 1, 1, 1, inf, inf]
- Tap 1: [0,5]. dp[1..5] = min(cur, dp[0..1]+1) = 1. dp=[0, 1, 1, 1, 1, 1]
Level III: Optimal Greedy (Jump Game II Variation)
Intuition
This is equivalent to finding the minimum jumps to reach n. We transform each tap into a 'jump' from its left boundary to its right boundary.
Thought Process
- Preprocess: For each start point , find the maximum end point it can reach:
maxReach[left] = max(maxReach[left], right). - Now it's Jump Game II: Iterate from to , keeping track of the current coverage end and the farthest reach possible.
Pattern: Interval Coverage / Jump Game II
Detailed Dry Run
n=5, ranges=[3,4,1,1,0,0] MaxReach: [5, 0, 3, 0, 4, 5] (Index 0 can reach 5 via Tap 1)
| i | farthest | end | taps | Action |
|---|---|---|---|---|
| 0 | 5 | 0 | 1 | i == end, taps++, end = 5 |
| 1-4 | 5 | 5 | 1 | farthest doesn't change |
| Result: 1 |
Found an issue or have a suggestion?
Help us improve! Report bugs or suggest new features on our Telegram group.