题目描述
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
输入: [2,3,1,1,4] 输出: true 解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4] 输出: false 解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
https://leetcode-cn.com/problems/jump-game/
解法1
解法1的方法是一种暴力搜索的方法,既然给出了每个位置能跳跃的最大距离,那我们就挨个尝试能落下的位置,然后以该位置为起点继续重复此过程看看能不能到达末尾。这是一种DFS方法,时间复杂度为O(n^2)。这种做法属于“人思考的少,机器思考的多”,另外代码量也很大,所以不推荐这种做法。
class Solution {
public boolean canJump(int[] nums) {
if (nums.length == 0)
return false;
int[] cache = new int[nums.length];
for (int i = 0; i < cache.length; i++)
cache[i] = -1;
return canJump(nums, 0, cache);
}
public boolean canJump(int[] nums, int start, int[] cache) {
if (cache[start] != -1)
return cache[start] == 1;
if (start == nums.length - 1)
return true;
int steps = nums[start];
boolean can = false;
for (int i = 1; i <= steps; i++)
if (start + i < nums.length) {
can |= canJump(nums, start + i, cache);
}
if (can)
cache[start] = 1;
else
cache[start] = 0;
return can;
}
}
解法2
解法2采用贪心的做法,设置一个变量currMax,表示从当前位置之前的任意一点出发能走到的最远的位置。我们遍历每一个位置,判断i是否大于currMax。如果i>currMax,物理意义表示从i之前的任意位置出发,都到达不了i,则肯定到达不了i之后的任何位置,返回false即可。否则,我们更新currMax = max(currMax, i + nums[i])。
class Solution {
public boolean canJump(int[] nums) {
int currMax = 0; // 表示从i之前的任意一点出发能走到的最远位置
for(int i=0;i<nums.length;i++){
if(i > currMax) return false;
currMax = Math.max(currMax, i + nums[i]);
}
return true;
}
}
解法3
解法3采用回溯的方法,我们从终点向前回溯,看看终点之前有没有一个点i至少能够到达终点的,如果存在则回溯到点i;我们再看看i之前有没有一个点至少能够到达点i,如果存在我们继续回溯……直到看看能不能回溯到起点。如果能够回溯到起点,那我们从起点正向出发也一定能够到达终点;反之如果不能回溯到起点,那我们就没办法到达终点。
class Solution {
public boolean canJump(int[] nums) {
int lastStart = nums.length - 1;
for(int start = nums.length-2;start>=0;start--){
if(nums[start] >= lastStart - start){
lastStart = start;
}
}
return lastStart == 0;
}
}