LeetCode(跳跃游戏)

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值