LeetCode55. 跳跃游戏的两种解法:动态规划和贪心算法

题目概述:

在这里插入图片描述
题目链接:点我做题

题解:

一、动态规划

  因为我看的dp标签进的这个题,所以先想了个动态规划的方法,思路主要是这样的:
  定义一个size个元素的dp数组,dp[i]=true,when当前位置可以通过前面的跳跃到达,dp[i]=false,when当前位置不可以通过前面的跳跃到达,先使得dp[0]=true;,表明从0位置出发;
  然后根据nums[0]的值,更新 d p [ 1 ] 到 d p [ m i n ( s i z e − 1 , 0 + n u m s [ 0 ] ) ] dp[1]到dp[min(size - 1, 0 + nums[0])] dp[1]dp[min(size1,0+nums[0])]都为true,表明这些位置可以到达,
  然后从1开始往后遍历,每一个位置都先检查一下是否已经是true了,如果是,则可以进去仿照0位置更新 d p dp dp数组,由于STL的vector默认初始化的初始值是0,所以 d p [ s i z e − 1 ] dp[size - 1] dp[size1]默认会被初始化成 f a l s e false false,遍历完了以后就返回 d p [ s i z e − 1 ] dp[size - 1] dp[size1]的值就可以了。
代码:

class Solution {
public:
    bool canJump(vector<int>& nums) 
    {
        int size = nums.size();
        vector<bool> dp(size);
        dp[0] = true;
        for (int i = 0; i <= nums[0]; ++i)
        {
            if (i >= size)
            {
                break;
            }
            dp[i] = true;
        }
        for (int i = 1; i < size - 1; ++i)
        {
            if (dp[i] == true)
            {
                for (int j = 1; j <= nums[i]; ++j)
                {
                    if (i + j >= size)
                    {
                        break;
                    }
                    dp[i + j] = true;
                }
            }
            if (dp[size - 1] == true)
            {
                break;
            }
        }
        return dp[size - 1];
    }
};

  这个代码有一个可以优化的地方,如果进来发现dp[i]等于false了,应该直接return false;,因为连i位置都不能通过前面的跳跃到达的话,那么是不可能到达size-1这个位置的,因为每轮其实都会跟更新当前能到达的最右位置的dp为true,如果你进入的位置是false,说明前一轮能到达的最右位置在这之前,那么你是永远到达不了这个位置的,既然你到达不了这个位置,那后面的位置肯定也到达不了,因为规则规定你可以跳1步、跳2步、跳3步…跳nums[i]步,能到达的位置一定是连续的,这位置到达不了那下一个位置肯定也到达不了,最右到达位置就不会更新了,所以size -1肯定也到达不了
时间复杂度: O ( n ∗ m a x i ( n u m s [ i ] ) ) O(n*max_{i}(nums[i])) O(nmaxi(nums[i]))
空间复杂度: O ( n ) O(n) O(n)

二、贪心算法

  其实注意到的每一个位置都会实时更新最右到达位置这点的时候,就应该想到这个方法。
  维护一个最右到达位置,初始值是0,表明此时0下标可以到达;
  然后通过位置0的nums[0]值更新最右到达位置,此时最右到达位置为 m a x ( 0 , 0 + n u m s [ 0 ] ) max(0, 0 +nums[0]) max(0,0+nums[0]);
  然后从下标为1的位置出发,遍历一遍nums数组,先检查此时的最右到达位置是否覆盖了次位置,如果没有覆盖,正如我们在动态规划里说的一样,直接返回break出去返回false就行;
  否则进去更新最右到达位置为: r i g h t m a x = m a x ( r i g h t m a x , i + n u m s [ i ] ) ; rightmax = max(rightmax, i + nums[i]); rightmax=max(rightmax,i+nums[i]);
  每轮循环最后,检查当前最优到达位置是否已经大于 s i z e − 1 size - 1 size1,如果大于了,说明已经可以到达尾巴了,返回 t r u e true true就可以。
代码:

class Solution {
public:
    bool canJump(vector<int>& nums) 
    {
        //贪心算法
        //维护一个最大到达下标rightmax,初始值为0
        //如果我们的当前下标小于最大到达下标,则表明当前下标可以通过前面的跳跃到达
        //然后更新最大到达下标为rightmax = rightmax + nums[i]
        //然后检查rightmax是否大于size - 1
        //如果大于 则return true
        //如果当前下标大于最大到达下标 说明当前位置已经不可以到达 直接return false
        int size = nums.size();
        int rightmax = 0;
        for (int i = 0; i < size; ++i)
        {
            if (i <= rightmax)
            {
                rightmax = max(rightmax, i + nums[i]);
            }
            else
            {
                break;
            }
            if (rightmax >= size - 1)
            {
                return true;
            }
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值