新的一年,从重拾Leetcode开始!
题目内容
在 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 解释:即使打开所有水龙头,你也无法灌溉整个花园。
示例 3:
输入:n = 7, ranges = [1,2,1,0,2,1,0,1] 输出:3
示例 4:
输入:n = 8, ranges = [4,0,0,0,0,0,0,0,4] 输出:2
示例 5:
输入:n = 8, ranges = [4,0,0,0,4,0,0,0,4] 输出:1
提示:
1 <= n <= 10^4
ranges.length == n + 1
0 <= ranges[i] <= 100
题目分析
最开始被这道题目Hard的标识吓住了,感觉这道题目一定不简单,但事实证明,这个题思路和代码都是十分简洁的,有之前类似的题目可以借鉴。
首先,考虑的是集合交并补的一些运算,绕来绕去把我绕晕了。接着,这个题目我开始想是不是应该采用贪心算法,但是在具体如何贪心上,我陷入了疑惑。最开始,我想,我们可以从位置0开始向后寻找能到达的第一个最远的点,然后,从第一个最远的点继续出发,一直到达最右端位置。但是如果是这样,如果我们恰好跳到了数值为0的点,我们就没法继续向后找了。思考到这里的时候,就会发现这个题目和Leetcode 跳跃游戏Ⅱ极为相似,这道题目中所谓的跳跃长度,就是这道题目中的灌溉范围,所谓最少几个水龙头,就是问最少跳跃几次。回忆跳跃游戏这道经典的贪心算法题目,我们使用了一个数组reach[i],记录从i这个位置最远可以跳跃到reach[i]。reach[i]的更新思路也很简单,我们选择在所有i能跳到的位置中,能到达最远的那个位置。也就是说,如果我们记start = i-ranges[i],end = i+ ranges[i],我们去找start和end之间的reach[j]和end的最大值。如果我们得到的最大值还是它本身(没有办法跳到其他位置),那么我们就返回-1。
代码
class Solution {
public int minTaps(int n, int[] ranges) {
int[] reach = new int[n+1];
for(int i=0;i<=n;i++)
{
int start = Math.max(0, i-ranges[i]);
int end = Math.min(n,i+ranges[i]);
for(int j=start;j<=end;j++)
{
reach[j] = Math.max(end,reach[j]);
}
}
int res = 0;
int curPos = 0;
while(curPos<n)
{
if(reach[curPos]<=curPos)
{
return -1;
}
curPos = reach[curPos];
res++;
}
return res;
}
}
祝大家新春快乐,在新的一年工作顺顺利利,身体健健康康!