20200404
题目 :跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否可以到达最后的位置。
示例:
输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
answer1
- 利用递归回溯模拟从第一个位置跳到最后位置的所有方案
- 递归算法的本质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。
本程序执行思路:
- 首先有递归调用的结束条件,不然会一直执行,导致栈溢出。
if(position == nums.length - 1){
return true;
}
- 执行递归方法,不断把一个大问题分解成小问题,直到满足递归结束的条件,此时开始返回上一级方法。
if(canJumpPosition(nextPostion,nums))
- 当这个满足时,就返回
true
,之后不断返回true
。
code
class Solution{
public boolean canJump(int[] nums){
return canJumpFromPosition(0,nums);
}
public boolean canJumpFromPostion(int postion,int nums){
//递归的结束条件
if(position == nums.length - 1){
return true;
}
int furthestJump = Math.min(postion + nums[postion],nums.length -1);
for(int nextPositon = position + 1; nextPosition <= furthJump;nextPostion++){
if(canJumpFromPosition(nextPosition,nums)){
return true;
}
}
return false;
}
}
answer2 :自顶向下的动态规划
优化回溯算法
利用一个记录数组memo进行记录,优化递归。
步骤
- 初始化
memo
的所有元素为UNKNOWN,除了最后一个为GOOD - 优化递归算法,每步回溯前先检查这个位置是否计算过。
- 如果已知直接返回结果True/False
- 否则按照之前的回溯步骤计算
code
enum Index{
GOOD,BAD,UNKNOWN
}
public class Solution{
Index[] memo;
public boolean canJumpFromPostion(int position, int[] nums){
if(memo[position] != Index.UNKNOWN){
return memo[position] == Index.GOOD ? true : false;
}
int furthestJump = Math.min(position + nums[position],nums.length-1);
for(int nextPosition = position + 1; nextPosition <= furthestJump;nextPosition++){
if(canJumpFromPostion(nextPosition, nums)){
memo[position] = Index.GOOD;
return true;
}
}
memo[position] = Index.BAD;
return false;
}
public boolean canJump(int[] nums){
memo = new Index[nums.length];
for(int i=0;i<memo.length;i++){
memo[i] = Index.UNKNOWN;
}
memo[memo.length-1] = Index.GOOD;
return canJumpFromPosition(0,nums);
}
}
answer3 :自底向上的动态规划
自底向上和自顶向下动态规划的区别就是消除了回溯,在实际使用中,自底向上的方法有更好时间效率。我们从右边开始动态规划,每次查询右边节点的信息,都是已经计算过的,不再需要额外的递归开销。
code
enum Index{
GOOD,BAD,UNKNWON
}
public class Solution{
public boolean canJump(int[] nums){
Index[] meomo = new Index[nums.length];
for(int i=0;i<memo.length;i++){
memo[i] = Index.UNKNOWN;
}
memo[memo.length - 1] = Index.GOOD;
for(int i=numslength - 2;i>=0;i--){
int furthestJump = Math.min(i + nums[i],nums.length-1);
for(int j=i+1;j<=furthestJump;j++){
if(memo[j] == Index.GOOD){
memo[i] = Index.GOOD;
break;
}
}
}
return memo[0] == Index.GOOD;
}
}