LeetCode 55. 跳跃游戏(Jump Game)I II tag 数组 贪心 动态规划

labuladong

一、

题目描述

 

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

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

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

 

示例 1:

输入: [2,3,1,1,4]
输出: true
解释: 从位置 0 到 1 跳 1 步, 然后跳 3 步到达最后一个位置。

示例 2:

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

思路一:
使用动态规划的想法,用额外的数组记录可以到达的位置,然后通过reach[n-1]来判断
可以解题,但是速度太慢。
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n=nums.size();
        if(n<2)
            return true;
        vector<bool> reach(n,false);
        reach[0]=true;
        for(int i=0;i<n;++i)
        {
            if(reach[i])
            {
                for(int j=1;j<=nums[i]&&i+j<n;j++)
                {
                    reach[i+j]=true;
                }
                if(reach[n-1])
                    return true;
            }
        }
        return reach[n-1];
    }
};

 

思路二:
    • 每次到一个位置 i,判断 maxS 最远可到的位置下标能不能到达 i
    • 能到达,则在当前位置可达的最远位置下标为 nums[i] + i , 取其与 maxS 的大者为最远可达位置
    • 循环判断
      在这里插入图片描述
class Solution {
public:
    bool canJump(vector<int>& nums) {
         int maxS = 0, i;
         for(i = 0; i < nums.size(); ++i)
         {
             if(maxS < i)
                 return false;
             maxS = max(maxS, nums[i]+i);
         }
         return true;
    }
};

 

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n=nums.size();
        int maxLen=0;
        for(int i=0;i<n;++i)
        {
            if(i<=maxLen)
            {
                maxLen=max(maxLen, i+nums[i]);
                if(maxLen>=n-1)
                    return true;
            }
        }
        return false;
    }
};

 

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int n=nums.size();
        int fartest=0;
        //i到n-1时就已经满足了条件
        for(int i=0;i<n-1;++i){
            fartest=max(fartest, i+nums[i]);
            //到i时,最大距离仍旧不超过i,意味着到达不了下一位
            if(fartest<=i){
                return false;
            }
        }
        //能否到达n-1位置
        return fartest>=n-1;
    }
};

 

二、

题目描述

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

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

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:

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

说明:假设你总是可以到达数组的最后一个位置。

 

思路:

这道题的最优解是可以时间复杂度优化到 O(n) 的,那就是采用贪心算法,我们从左边的起点开始跳跃的时候,我们应该跳跃到哪一个点比较合适呢?,显然,每次都跳跃最大长度的话,是不行的。例如对于上面 arr = {2, 3, 1, 1, 4, 2, 1} 这个例子,刚开 arr[0] = 2,那么我们可以跳到 arr[1] = 3 或者 arr[2] = 1 上,显然,我们跳跃 arr[1] = 3 会更好一点。如图(图片来源于网络)

leetcode 第45题:跳跃游戏2

接着同样的道理,我们可以从 arr[1] = 3 这个位置开始跳跃,它可以跳跃到 arr[2] = 1, arr[3] = 1, arr[4] = 4 这三个位置,显然,我们跳到 arr[4] = 4 这个位置好一点,如图(图片来源于网络)

leetcode 第45题:跳跃游戏2

也就是说,我们要跳跃的那个点,可以使得上一次 + 下一次的跳跃总距离最远。代码如下

class Solution {
public:
    int jump(vector<int>& nums) {
        int step=0,end=0,maxS=0;
        for(int i=0;i<nums.size()-1;++i)
        {
            maxS=max(maxS,i+nums[i]);
            if(i==end)
            {
                end=maxS;
                step++;
            }
        }
        return step;
    }
};

 

class Solution {
public:
    int jump(vector<int>& nums) {
        int n=nums.size();
        int step=0;
        //end记录上一次跳跃的位置
        int farthest=0,end=0;
        for(int i=0;i<n-1;++i){
            farthest=max(farthest,i+nums[i]);
            //当end==i时,就意味着需要下一步跳跃
            if(end==i){
                step++;
                end=farthest;
            }

        }
        return step;
    }
};

 



posted @ 2021-03-09 20:46  鸭子船长  阅读(126)  评论(0编辑  收藏  举报