Minimum Number of Taps to Open to Water a Garden — Hard Problem & Solution
A garden stretches along the x-axis from 0 to n. Tap i sits at position i and, when opened, waters the closed interval [i - ranges[i], i + ranges[i]].
- Difficulty: Hard
- Topics: Arrays, Dynamic Programming, Greedy, Intervals
- Asked at: Amazon, Google, Flipkart
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
A garden stretches along the x-axis from 0 to n. Tap i sits at position i and, when opened, waters the closed interval [i - ranges[i], i + ranges[i]].
Return the minimum number of taps to open so that the whole garden is watered, or -1 if it is impossible.
Example 1
Input: n = 5, ranges = [3,4,1,1,0,0]
Output: 1
Explanation: Tap 1 alone waters [-3, 5], which covers the garden.
Example 2
Input: n = 3, ranges = [0,0,0,0]
Output: -1
Explanation: Every tap waters only its own point, leaving the gaps dry.
Example 3
Input: n = 7, ranges = [1,2,1,0,2,1,0,1]
Output: 3
Constraints
1 <= n <= 10000ranges.length == n + 10 <= ranges[i] <= 100
How to solve Minimum Number of Taps to Open to Water a Garden
Convert the taps into intervals, keep only the furthest reach per starting point, then cover [0, n] greedily — from everything already watered, jump to the furthest point any of those taps reaches.
Approach
- Build
maxReach[l], the largest right endpoint among taps whose clamped interval starts atl. - Sweep
ifrom 0 ton - 1, trackingnxt, the furthest reach from any start seen so far. - At each boundary
curEnd, open a tap: ifnxt <= ithere is a dry gap and the answer is-1; otherwise count the tap and move the boundary tonxt.
Why it works
Only the furthest-reaching tap per start can be optimal — any other with the same start is contained in it. Committing at each boundary to the furthest reach is the classic covering greedy: delaying cannot reach further, and choosing a shorter interval forces at least as many taps later.
Complexity
- Time —
O(n) - Space —
O(n)
Pitfalls
- The intervals must be clamped to
[0, n]before indexing, or a tap with a large range reads out of bounds. - A tap with range 0 waters a single point and can never bridge a gap.
- The failure test is
nxt <= iat a boundary — equality means no progress.
Reference solution
Python
from typing import List
def minTaps(n: int, ranges: List[int]) -> int:
max_reach = [0] * (n + 1)
for i, r in enumerate(ranges):
l = max(0, i - r)
right = min(n, i + r)
max_reach[l] = max(max_reach[l], right)
taps = cur_end = nxt = 0
for i in range(n):
nxt = max(nxt, max_reach[i])
if i == cur_end:
if nxt <= i:
return -1
taps += 1
cur_end = nxt
return tapsJavaScript
var minTaps = function(n, ranges) {
var maxReach = [];
for (var t = 0; t <= n; t++) maxReach.push(0);
for (var i = 0; i <= n; i++) {
var l = Math.max(0, i - ranges[i]);
var r = Math.min(n, i + ranges[i]);
if (r > maxReach[l]) maxReach[l] = r;
}
var taps = 0, curEnd = 0, nxt = 0;
for (var j = 0; j < n; j++) {
if (maxReach[j] > nxt) nxt = maxReach[j];
if (j === curEnd) {
if (nxt <= j) return -1;
taps++;
curEnd = nxt;
}
}
return taps;
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.