一. 因为求解的是一个最优化问题,所以第一个想到的是动态规划,但是很可惜的是超时了.......
//令dp[i]为可以跳跃到i的最小跳跃次数.
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 0);
dp[0] = 0;
for (int i = 1; i < n; i++) {
//令第一个为INT_MAX,因为接下来要进行min的比较.
dp[i] = INT_MAX;
for (int j = i - 1; j >= 0; j--) {
if (nums[j] + j >= i) {
//找到最小的跳跃次数.
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
return dp[n - 1];
}
};
二. 直接参考题解了.....
作者:windliang
链接:https://leetcode-cn.com/problems/jump-game-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-10/
1. 解法一 :顺藤摸瓜
2. 贪婪算法,我们每次在可跳范围内选择可以使得跳的更远的位置。每次找局部最优,最后达到全局最优.
3. 写代码的话,我们用 end 表示当前能跳的边界,遍历数组的时候,到了边界,我们就重新更新新的边界。
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
int end = 0;//可以跳的最远的位置.
int step = 0;//记录跳跃次数.
int maxv = 0;//更新跳的最远的距离.
//i<n-1,因为跳到最后不用更新边界.
for (int i = 0; i < n - 1; i++) {
//记录跳的最远的位置.
maxv = max(maxv, nums[i] + i);
if (i == end) {
//如果到达边界,则更新边界,并令次数加1.
end = maxv;
step++;
}
}
return step;
}
};
时间复杂度:O(n)。
空间复杂度:O(1)。
4. 这里要注意一个细节,就是 for 循环中,i < nums.length - 1,少了末尾。因为开始的时候边界是第 0 个位置,steps 已经加 1 了。如果最后一步刚好跳到了末尾,此时 steps 其实不用加 1 了。如果是 i < nums.length,i 遍历到最后的时候,会进入 if 语句中,steps 会多加 1。
5. 解法二:顺瓜摸藤
第二个思路和动态规划差不多,不过时间复杂度比他低一点,因为有break.
我们知道最终要到达最后一个位置,然后我们找前一个位置,遍历数组,找到能到达它的位置,离它最远的就是要找的位置。然后继续找上上个位置,最后到了第 0 个位置就结束了。至于离它最远的位置,其实我们从左到右遍历数组,第一个满足的位置就是我们要找的。
//超时
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
int steps = 0;
int last = n - 1;
while (last != 0) {
for (int j = 0; j < last; j++) {
if (nums[j] + j >= last) {
last = j;
steps++;
break;
}
}
}
return steps;
}
};
可惜的是还是超时了.........
6. 改进的dp, 思路有点意思, 思想还是贪心.
//改进的dp,思路有点意思.
class Solution {
public:
int jump(vector<int>& nums) {
int n = nums.size();
//base,如果长度为1,则不需要跳跃.
if (n == 1) {
return 0;
}
//dp[i]的含义是以i结尾最少跳跃次数.
vector<int> dp(n, 0);
for (int i = 0; i < n - 1; i++) {
//查找从i所能跳跃到的位置,i+j.
for (int j = nums[i]; j > 0; j--) {
//如果i能跳到最后直接return.
//而且第一个return的一定是次数最少的.
if (i + j >= n - 1) {
return dp[i] + 1;
}
//如果i+j没跳到,则为dp[i]+1.
if (dp[i + j] == 0) {
dp[i + j] = dp[i] + 1;
}
//如果已经有值了,说明被提前访问到.
//那就直接break,因为次数不可能最少.
else
break;
}
}
return -1;
}
};