【贪心算法】跳跃游戏

跳跃游戏

给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个位置。

示例 1:

输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/jump-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我们先用动态规划来求解:

我们维护一个dp数组表示当前位置能到达的最远位置。当dp[i-1] 的值大于 nums.size()-1时,表示我们可以到达数组最大下标。

那么dp数组的更新过程:

for(int i = 1;i < nums.size();i ++){
    if(dp[i-1] >= nums.size()-1) return true; //i-1位置已经可以跳到数组的最后一个位置,返回true
    //i-1位置可以到达i,那么继续向前,并且dp[i]取i-1位置可以达到的最远距离和i位置加上nums[i]的步长可以达到的最远距离的最值
    if(i <= dp[i-1])  dp[i] = max(dp[i-1],i + nums[i]); 
    else break; //i-1位置到达不了i,跳出循环

完整代码:

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size() == 1) return true; //出道即巅峰
        vector<int> dp(nums.size()); //dp数组表示当前位置可以达到的最远位置
        dp[0] = nums[0]; //0位置的最大长度
        for(int i = 1;i < nums.size();i ++){
            if(dp[i-1] >= nums.size()-1) return true; 
            if(i <= dp[i-1])  dp[i] = max(dp[i-1],i + nums[i]); 
            else break; //i-1位置到达不了i,跳出循环
        }
        return false; //不能到达最后一个位置
    }
};

很清晰的动态规划思路,时间复杂度o(n),空间复杂度o(n),运行结果:

紧接着我们进行优化,既然dp[i]状态之和dp[i-1]有关,那么我们只需要维持一个变量表示dp[i-1]就行。

这也就是贪心算法的一个应用了,只观察当前的位置能不能由上一个位置到达。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int rightMost = 0;
        for(int i = 0;i < nums.size();i ++){
            if(rightMost >= nums.size()-1) return true; //已经可以到达数组最后一位
            if(i <= rightMost) rightMost = max(rightMost,i+nums[i]); //更新最远距离
            else break; //中途失败
        }
        return false; 
    }
};

短小精悍,空间复杂度降到o(1)。

继续再发挥一点人类才智:

不到达的情况就是有一个位置的跳数为0,那么我们从后往前找到一个跳数为0的点,然后寻找它前面有没有可以跳过这个位置到达下一个位置的点。

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size() == 1) return true; //出道即巅峰
        for(int i = nums.size()-2;i >= 0;i --){ //从倒数第二个位置开始遍历
            if(nums[i] == 0){ //该位置跳数为0
                int k;
                for(k = i-1;k >= 0;k --) if(nums[k] > i - k) break; //从k起跳可以避免跳到i
                if(k == -1) return false; //没有找到可以跳过i的位置
            }
        }
        return true;
    }
};

可以想象最后一种一定是最快的,所以贪心算法套路不固定,所以使用范围有限,当它的时间复杂度能比动态规划更优时,使用意义最大。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jiawen9

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

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

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

打赏作者

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

抵扣说明:

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

余额充值