在 x 轴上有一个一维的花园。花园长度为 n
,从点 0
开始,到点 n
结束。
花园里总共有 n + 1
个水龙头,分别位于 [0, 1, ..., n]
。
给你一个整数 n
和一个长度为 n + 1
的整数数组 ranges
,其中 ranges[i]
(下标从 0 开始)表示:如果打开点 i
处的水龙头,可以灌溉的区域为 [i - ranges[i], i + ranges[i]]
。
请你返回可以灌溉整个花园的 最少水龙头数目 。如果花园始终存在无法灌溉到的地方,请你返回 -1 。
示例 1:
输入:n = 5, ranges = [3,4,1,1,0,0] 输出:1 解释: 点 0 处的水龙头可以灌溉区间 [-3,3] 点 1 处的水龙头可以灌溉区间 [-3,5] 点 2 处的水龙头可以灌溉区间 [1,3] 点 3 处的水龙头可以灌溉区间 [2,4] 点 4 处的水龙头可以灌溉区间 [4,4] 点 5 处的水龙头可以灌溉区间 [5,5] 只需要打开点 1 处的水龙头即可灌溉整个花园 [0,5] 。
示例 2:
输入:n = 3, ranges = [0,0,0,0] 输出:-1 解释:即使打开所有水龙头,你也无法灌溉整个花园。
提示:
1 <= n <= 104
ranges.length == n + 1
0 <= ranges[i] <= 100
方法一:贪心
注意到,对于所有能覆盖某个左端点的水龙头,选择能覆盖最远右端点的那个水龙头是最优的。
因此,我们可以预处理 ranges
,对于每一个位置 l = max(0, i-ranges[i])
和 r = min(n, i+ranges[i])
,我们算出所有能覆盖左端点
我们定义变量 mx
表示当前能够到达的最远位置,变量 ans
表示当前需要的最少子区间数,变量 pre
表示上一个被使用的子区间的右端点。
接下来,我们从 mx
。如果更新后
同时我们记录上一个被使用的子区间的右端点 pre
,如果 ans
加 pre
更新为 mx
。
遍历结束后,返回 ans
即可。
时间复杂度
相似题目:
class Solution:
def minTaps(self, n: int, ranges: List[int]) -> int:
last = [0] * (n + 1)
for i, v in enumerate(ranges):
l, r = max(0, i - v), min(n, i + v)
last[l] = max(last[l], r)
ans = mx = pre = 0
for i in range(n):
mx = max(mx, last[i])
if mx <= i:
return -1
if pre == i:
ans += 1
pre = mx
return ans
class Solution {
public int minTaps(int n, int[] ranges) {
int[] last = new int[n + 1];
for (int i = 0; i < n + 1; ++i) {
int v = ranges[i];
int l = Math.max(0, i - v), r = Math.min(n, i + v);
last[l] = Math.max(last[l], r);
}
int ans = 0, mx = 0, pre = 0;
for (int i = 0; i < n; ++i) {
mx = Math.max(mx, last[i]);
if (mx <= i) {
return -1;
}
if (pre == i) {
++ans;
pre = mx;
}
}
return ans;
}
}
class Solution {
public:
int minTaps(int n, vector<int>& ranges) {
vector<int> last(n + 1);
for (int i = 0; i < n + 1; ++i) {
int v = ranges[i];
int l = max(0, i - v), r = min(n, i + v);
last[l] = max(last[l], r);
}
int ans = 0, mx = 0, pre = 0;
for (int i = 0; i < n; ++i) {
mx = max(mx, last[i]);
if (mx <= i) {
return -1;
}
if (pre == i) {
++ans;
pre = mx;
}
}
return ans;
}
};
func minTaps(n int, ranges []int) int {
last := make([]int, n+1)
for i, v := range ranges {
l, r := max(0, i-v), min(n, i+v)
last[l] = max(last[l], r)
}
ans, mx, pre := 0, 0, 0
for i := 0; i < n; i++ {
mx = max(mx, last[i])
if mx <= i {
return -1
}
if pre == i {
ans++
pre = mx
}
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func min(a, b int) int {
if a < b {
return a
}
return b
}