题目描述
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个位置。
示例 1:
输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:
输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。
解法1
1.1 Top Down
思路:从头开始搜索,用一个memo来记录每个对应index是否为通路,{1:通路;-1:非通路;0:未知}. 使用递归查找,如果index能到达的路径中存在一条通路,就在memo中将这个index的值设为1;反之则为-1
class Solution {
public boolean canJump(int[] nums) {
boolean isReachable;
int[] memo = new int[nums.length];
Arrays.fill(memo, 0);
memo[memo.length - 1] = 1;
if (nums.length < 2) isReachable = true;
else
{
isReachable = isWithinReach(memo, nums, 0);
}
return isReachable;
}
public boolean isWithinReach(int[] memo, int[] nums, int currIndex)
{
if (memo[currIndex] == 1) return true;
else if (memo[currIndex] == -1) return false;
else
{
int MaxReach = Math.min(currIndex + nums[currIndex], nums.length - 1);
for (int i = currIndex + 1; i <= MaxReach; i++)
{
boolean jumpResult = isWithinReach(memo, nums, i);
if (jumpResult)
{
memo[currIndex] = 1;
return true;
}
}
memo[currIndex] = -1;
return false;
}
}
}
1.2 Buttom Up
思路:延续1.1的memo法,实际做法就是把递归改成一个while循环
class Solution {
public boolean canJump(int[] nums) {
boolean isReachable = false;
int[] memo = new int[nums.length];
Arrays.fill(memo, 0);
memo[memo.length - 1] = 1;
if (nums.length < 2) isReachable = true;
else
{
for (int i = nums.length - 2; i >= 0; i--)
{
int MaxReach = Math.min(i + nums[i], nums.length - 1);
for (int j = i + 1; j <= MaxReach; j++)
{
if (memo[j] == 1)
{
memo[i] = 1;
break;
}
}
}
if (memo[0] == 1) isReachable = true;
}
return isReachable;
}
}
解法2 贪心算法
思路:解法1中最优的buttom up算法用了两个循环,还用了一个和nums一样长度的memo数组来记录。贪心算法有点类似最大子序和中的在线处理算法,只用一个循环,用一个int变量来记录。
class Solution {
public boolean canJump(int[] nums) {
int MaxJumpStep = 0;
for (int i = 0; i < nums.length; i++)
{
if (i > MaxJumpStep) return false;
if (MaxJumpStep >= nums.length - 1) return true;
MaxJumpStep = Math.max(MaxJumpStep, i + nums[i]);
}
return true;
}
}