You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a one-dimensional garden on the x-axis. The garden starts at the point 0 and ends at the point n. (i.e The length of the garden is n).
There are n + 1 taps located at points [0, 1, ..., n] in the garden.
Given an integer n and an integer array ranges of length n + 1 where ranges[i] (0-indexed) means the i-th tap can water the area [i - ranges[i], i + ranges[i]] if it was open.
Return the minimum number of taps that should be open to water the whole garden, If the garden cannot be watered return -1.
Example 1:
Input: n = 5, ranges = [3,4,1,1,0,0]
Output: 1
Explanation: The tap at point 0 can cover the interval [-3,3]
The tap at point 1 can cover the interval [-3,5]
The tap at point 2 can cover the interval [1,3]
The tap at point 3 can cover the interval [2,4]
The tap at point 4 can cover the interval [4,4]
The tap at point 5 can cover the interval [5,5]
Opening Only the second tap will water the whole garden [0,5]
Example 2:
Input: n = 3, ranges = [0,0,0,0]
Output: -1
Explanation: Even if you activate all the four taps you cannot water the whole garden.
Constraints:
1 <= n <= 104
ranges.length == n + 1
0 <= ranges[i] <= 100
这道题说是在x轴上有一个长度为n的花园,共有等距离的 n+1 喷头,现在有一个 ranges 数组,说是第i个喷头可以覆盖的范围是 [i - ranges[i], i + ranges[i]],问最少需要几个喷头可以覆盖整个花园。这道题跟之前那道 Video Stitching 基本上没有太大的区别,就是场景换了一下,本质都是一样的,类似的还有 Jump Game II。这道题可以使用贪婪算法 Greedy Algorithm 和动态规划 Dynamic Programming 来做,先来用贪婪算法,采用和 Jump Game II 一样的思路。
这里将题目也看成跳跃游戏的场景,从位置0开始,看是否能跳到位置n。那么就需要知道每个点的跳力,于是来构建 jumps 数组。对于每个喷头,题目说了其覆盖范围是 [i - ranges[i], i + ranges[i]],为了防止其越界,左边界点 left 就取 max(0, i - ranges[i]),右边界点 right 就取 min(n, i + ranges[i]),这样站在左边界点 left 上,其跳力就是 right - left,每次用这个来更新 jumps[left] 即可。有了 jumps 数组就可以开始计算最小跳跃数了,新建变量 farCanReach 表示当前最远能到达的位置,last 表示上次到达的最远位置。
然后开始遍历每个位置,若当前位置i大于 farCanReach,表示无法到达当前位置,即喷头无法覆盖整个花园,直接返回 -1。否则就用 i + jums[i] 来更新 farCanReach,因为当前的位置加上其跳力,就是其能到达的最远距离,若当前位置i等于 last 了,表示已经到达了上次跳跃的最远位置了,此时需要开始新的跳跃了,跳跃次数增1,last 更新为 farCanReach。以此类推,直到 for 循环推出后,判断若 farCanReach 大于等于n的话,表示可以到达末尾,返回结果 res,否则返回 -1 即可,参见代码如下:
解法一:
class Solution {
public:
int minTaps(int n, vector<int>& ranges) {
vector<int> jumps(n + 1);
for (int i = 0; i < n + 1; ++i) {
int left = max(0, i - ranges[i]);
int right = min(n, i + ranges[i]);
jumps[left] = max(jumps[left], right - left);
}
int res = 0, last = 0, farCanReach = 0;
for (int i = 0; i < n; ++i) {
if (i > farCanReach) return -1;
farCanReach = max(farCanReach, i + jumps[i]);
if (i == last) {
++res;
last = farCanReach;
}
}
return farCanReach >= n ? res : -1;
}
};
class Solution {
public:
int minTaps(int n, vector<int>& ranges) {
vector<int> dp(n + 1, n + 1);
dp[0] = 0;
for (int i = 0; i < n + 1; ++i) {
int left = max(0, i - ranges[i]);
int right = min(n, i + ranges[i]);
for (int j = left; j <= right; ++j) {
dp[j] = min(dp[j], 1 + dp[left]);
}
}
return (dp[n] == n + 1) ? -1 : dp[n];
}
};
There is a one-dimensional garden on the x-axis. The garden starts at the point
0
and ends at the pointn
. (i.e The length of the garden isn
).There are
n + 1
taps located at points[0, 1, ..., n]
in the garden.Given an integer
n
and an integer arrayranges
of lengthn + 1
whereranges[i]
(0-indexed) means thei-th
tap can water the area[i - ranges[i], i + ranges[i]]
if it was open.Return the minimum number of taps that should be open to water the whole garden, If the garden cannot be watered return -1.
Example 1:
Example 2:
Constraints:
1 <= n <= 104
ranges.length == n + 1
0 <= ranges[i] <= 100
这道题说是在x轴上有一个长度为n的花园,共有等距离的 n+1 喷头,现在有一个 ranges 数组,说是第i个喷头可以覆盖的范围是
[i - ranges[i], i + ranges[i]]
,问最少需要几个喷头可以覆盖整个花园。这道题跟之前那道 Video Stitching 基本上没有太大的区别,就是场景换了一下,本质都是一样的,类似的还有 Jump Game II。这道题可以使用贪婪算法 Greedy Algorithm 和动态规划 Dynamic Programming 来做,先来用贪婪算法,采用和 Jump Game II 一样的思路。这里将题目也看成跳跃游戏的场景,从位置0开始,看是否能跳到位置n。那么就需要知道每个点的跳力,于是来构建 jumps 数组。对于每个喷头,题目说了其覆盖范围是
[i - ranges[i], i + ranges[i]]
,为了防止其越界,左边界点 left 就取max(0, i - ranges[i])
,右边界点 right 就取min(n, i + ranges[i])
,这样站在左边界点 left 上,其跳力就是right - left
,每次用这个来更新 jumps[left] 即可。有了 jumps 数组就可以开始计算最小跳跃数了,新建变量 farCanReach 表示当前最远能到达的位置,last 表示上次到达的最远位置。然后开始遍历每个位置,若当前位置i大于 farCanReach,表示无法到达当前位置,即喷头无法覆盖整个花园,直接返回 -1。否则就用
i + jums[i]
来更新 farCanReach,因为当前的位置加上其跳力,就是其能到达的最远距离,若当前位置i等于 last 了,表示已经到达了上次跳跃的最远位置了,此时需要开始新的跳跃了,跳跃次数增1,last 更新为 farCanReach。以此类推,直到 for 循环推出后,判断若 farCanReach 大于等于n的话,表示可以到达末尾,返回结果 res,否则返回 -1 即可,参见代码如下:解法一:
再来看动态规划的解法,建立一个一维数组 DP,其中 dp[i] 表示覆盖范围 [0, i] 区间需要的最少喷头个数,最终结果会保存在 dp[n] 中。dp 数组长度为 n+1,每个数字初始化为 n+1,但 dp[0] 要初始化为0。接下来求状态转移方程,使用和 Video Stitching 中类似的方法,遍历 [0, n] 中的每一个喷头,然后计算其能覆盖范围的左右边界,注意还是要进行防越界处理,跟上面的解法相同。计算出喷头i的覆盖的范围 [left, right] 之后,遍历其范围内的每一个位置j,由于该区间内的每个点都是可以到达的,即相当于在 dp[left] 的基础上又增加了一个喷头,所以可以用
1 + dp[left]
来更新 dp[j],这就是状态转移方程。最终循环退出后,判断 dp[n] 是否等于初始值 n+1,是的话返回 -1,否则返回 dp[n] 即可,参见代码如下:解法二:
Github 同步地址:
#1326
类似题目:
Jump Game II
Video Stitching
参考资料:
https://leetcode.com/problems/minimum-number-of-taps-to-open-to-water-a-garden/
https://leetcode.com/problems/minimum-number-of-taps-to-open-to-water-a-garden/solutions/486517/c-o-n-no-sort-similar-to-jump-game-ii/
https://leetcode.com/problems/minimum-number-of-taps-to-open-to-water-a-garden/solutions/712660/dp-pattern-to-solve-3-similar-problems/
LeetCode All in One 题目讲解汇总(持续更新中...)
(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)
喜欢请点赞,疼爱请打赏❤️~.~
微信打赏
|
Venmo 打赏
---|---
The text was updated successfully, but these errors were encountered: