leetcode 21天动态规划入门——从0到0.5【Day04】小兔子的跳跃游戏 如果是你 你会怎样做

leetcode 21天动态规划入门——从0到0.5【Day04】小兔子的跳跃游戏

写在前面

到了动态规划的第四天啦~今天可是不寻常的一天,因为今天的题的动态转化方程虽然很简单就能推导出来,但是今天的两个动态转化方程都可以进行略微的转换,使得时间复杂度降低,话不多说,冲!!!

题目

题目一

  1. 跳跃游戏 难度系数:***
给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。
示例

示例1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,
从下标 0 到达下标 1,
 然后再从下标 1 跳 3 步到达最后一个下标。

示例2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。
但该下标的最大跳跃长度是 0 ,
 所以永远不可能到达最后一个下标。
提示

1 <= nums.length < 3*10^4
0 <= nums[i] <= 10^5

思路
动态规划老样子
模拟 一部分推出全局
需要维护一个临时数组dp来记录当前小兔子能跳到的最远距离。

根据示例就可以推算出动态转化方程:
当前能跳跃的最远距离是:

  • 当前位置+当前位置能跳的距离
  • 前一个位置能到达的最远距离

二者之间进行取最大值即当前能跳跃的最大距离。

dp[i] = Math.max(dp[i-1],nums[i]+i);

代码实现
class Solution {
    public boolean canJump(int[] nums) {
    	//特殊情况特殊处理
        if(nums.length < 2) return true;
        //维护一个dp数组
        int dp[] = new int [nums.length+1];
        //最远能跳多远
        int maxStep = nums[0];
        dp[0] = nums[0];
        //模拟推导
        for (int i = 1 ; i< nums.length ;i++){
        	//如果当前位置大于了能跳的最远位置直接返回false
            if (i > maxStep) return false;
            //动态转化方程
            dp[i] = Math.max(dp[i-1],nums[i]+i);
            //维护最远位置
            maxStep = Math.max(dp[i],maxStep);
            if(maxStep > nums.length) return true;
        }
        return true;
    }
}
执行结果

在这里插入图片描述

代码优化
想一想为什么会导致时间复杂度这么高呢?
因为你既维护了一个dp数组的同时又维护了一个最远步长
每次都需要经历O(n)次遍历 比较 故时间 消耗会更大
那么我们只维护一个最远步长 能否实现呢?

优化如下

class Solution {
    public boolean canJump(int[] nums) {
    	//维护一个能到达最远位置的变量替换dp数组
        int maxIndex = nums[0];
        for (int i = 0 ; i< nums.length ;i++){
            if(i > maxIndex )return false;
            maxIndex = Math.max(i+nums[i],maxIndex);
            if (maxIndex > nums.length)return true;
        }
        return true;
    }
}

执行结果

在这里插入图片描述
典型的用空间换时间的做法qwq

题目二

  1. 跳跃游戏 II 难度系数:****
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。
示例

示例1:

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
     从下标为 0 跳到下标为 1 的位置,跳 1 步,
     然后跳 3 步到达数组的最后一个位置。

示例2:

输入: nums = [2,3,0,1,4]
输出: 2
提示

1 <= nums.length <= 10^4
0 <= nums[i] <= 1000

思路
维护一个dp[]数组用来表示到达第i个位置时所需要的最小步数。
思路在哪里?
思路在于 到达最后一个点之前有很多点都能够一步到达这个点
这就是求解动态转化方程的思路:

用一个指针遍历dp找到所有的位置能到的最小步数,用另一个指针来遍历dp获取得到离最后一个点最远的能够一次到达最后一个点的指针位置。
获得动态转化方程:
dp[i] = dp[j] + 1

代码实现
class Solution {
    public int jump(int[] nums) {
        if (nums.length<2)return 0;
        int[] dp = new int[nums.length]; 
        dp[0] = 0;
        //i是代表当前能跳跃的最远位置
        for (int i = 1, j = 0; i < nums.length; i++) {
        	//如果当前能到达的位置<最远需要到达的位置j指针后移
            while (j + nums[j] < i) j++;
            //动态转化方程 进行dp[i]赋值
            dp[i] = dp[j] + 1;
        }
        //维护的数组返回的是到达位置n需要的最小步数
        return dp[nums.length - 1];
    }
}
执行结果

在这里插入图片描述
双百! 这是来自宫水三叶小姐姐的思路(DP+贪心+双指针)的巧妙结合
学会了没? 学费了没?

写在最后

DAY4的动态规划是否让你感觉到不一样的难度?
今天不只是简单的寻找动态转化方程,
而更多地在于如何根据方程来优化维护的数组。
用更巧妙地方法,解决复杂的问题
加油 ~坚持打卡第四天!
最后
每天进步点 每天收获点
愿诸君 事业有成 学有所获
如果觉得不错 别忘啦一键三连哦~

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alascanfu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值