给定一个非负整数,你最初位于数组的第一个位置,数组中的每个元素代表你在该位置可以跳跃的最大长度,判断你是否能够到达最后一个位置
示例一
输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例二
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
简单暴力的递归回溯
从第一个位置开始,根据其可以跳跃的距离进行一个个跳跃,递归搜索,如果递归到0,则返回,继续下一个,直到遍历完所有方案或者找到一个可以到达的方案。
实现:
class Solution {
public:
bool canJump(vector<int>& nums) {
return _canJump(nums, 0);
}
// 递归搜索的方法
bool _canJump(vector<int> nums, int index) {
if(index + 1 >= nums.size()) {
return true;
}
if(nums[index] == 0){
return false;
}
// 可以跳跃的方案
int count = nums[index];
// 穷举每一个跳跃的方案
while(count > 0) {
// 如果其中一个方案可行,就返回true
if( count + index < nums.size() && _canJump(nums, index + count)) {
return true;
}
count--;
}
return false;
}
};
时间复杂度: 2^n,这样的时间复杂度是不太可行的,稍微大一点的数据就会造成超时,不可取
动态规划方法
对于暴力的回溯方法,我们可以发现数组长度是一定的,但是在递归搜索的过程中每个位置是否能走到最后一位,这个结果我们重复计算了很多次,造成了不必要的空间开销。而常规的方法便是引入缓存,新建一个跟数组一样长度的数组,用 -1 、 0 、 1分别表示走不通、未计算、能走通三个状态。然后在递归的初始阶段我们判断这个位置是否被计算过,如果没有被计算过,则继续走下去计算、否则,直接返回计算过的结果
实现:
class Solution {
public:
bool canJump(vector<int>& nums) {
int memo[nums.size()];
for(int i = 0; i < nums.size() - 1; i++) {
memo[i] = 0;
}
memo[nums.size() - 1] = 1;
return _canJump(nums, memo, 0);
}
bool _canJump(vector<int> nums, int memo[], int index) {
if(memo[index] != 0) {
return memo[index] == 1 ? true : false;
}
if(index + 1 >= nums.size()) {
memo[index] = 1;
return true;
}
if(nums[index] == 0){
memo[index] = -1;
return false;
}
int count = nums[index];
while(count > 0) {
if( count + index < nums.size() && _canJump(nums, memo, index + count)) {
memo[index] = 1;
return true;
}
count--;
}
memo[index] = -1;
return false;
}
};
时间复杂度O(n^2)
贪心做法
从后往前找:标记最后一个位置,向前寻找能到达最后一个位置的位置,更新标记为找到的该位置,继续向前找,遍历完毕之后,如果标志位为0,则能达到,如果标志位不为0,则不可以到达
从前往后找:从第一个位置开始,设置一个标志为能到达的最远位置,将当前所在所在位跟能跳跃的位置相加,再跟当前所能跳跃的最远位置相比较从而更新最远位置,一旦当前遍历的位置大于能够跳跃的最远位置,则不能达到,返回false,如果最后能遍历完,则表示能到达,返回true。
贪心从后往前遍历:
class Solution {
public:
bool canJump(vector<int>& nums) {
int lastPos = nums.size() - 1;
for (int i = nums.size() - 1; i >= 0; i--) {
if (i + nums[i] >= lastPos) {
lastPos = i;
}
}
return lastPos == 0;
}
};
贪心从前往后遍历:
class Solution {
public:
bool canJump(vector<int>& nums) {
int k = 0;
for(int i = 0; i < nums.size(); i++) {
if(i > k) {
return false;
}
k = max(k, i + nums[i]);
}
return true;
}
};
参考:题解
官方题解