【力扣-贪心】5、跳跃游戏I(55)II(45)

「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

55. 跳跃游戏

题目描述

给定一个非负整数数组 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步还是几步,只需要判断 调到的一格 是否能跳到最后一个数组元素位置,每次取最大的跳跃步数,判断是否有元素的跳跃范围达到最大的数组数目。

  • 贪心算法:
    • 局部最优:每次取最大的跳跃距离
    • 全局最优:最后判断局部最优中是否有能满足条件的,满足则就是全局最优的结果

代码

class Solution
{
public:
   bool canJump(vector<int> &nums)
   {
       int cover = 0;
       if (nums.size() == 1)
       {
           return true;
       }

       for (int i = 0; i <= cover; i++)
       {
           // 记录每一步的最大跳跃范围
           cover = max(i + nums[i], cover);
           // 如果跳跃的范围能够满足数组的数目,则可以到达最后一个下标
           if (cover >= nums.size() - 1)
           {
               return true;
           }
       }
   }
};
复制代码

45. 跳跃游戏 II

题目描述

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

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

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

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

示例 1:

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

示例 2:

输入: nums = [2,3,0,1,4]
输出: 2
复制代码

解析

与上一题思路相似,判断每一步能够到达的最远下标。如果当前能到达最远下标,则停止;如果不能到达最远下标,就继续走一步,判断下一步能否到达最远下标。

  • 当移动下标到达了当前覆盖的最远距离下标时:
    • 1、如果当前覆盖的最远距离下标时终点,直接返回,不需再走一步
    • 2、如果当前覆盖的最远距离下标不是终点,需要再走一步

代码

class Solution
{
public:
    int jump(vector<int> &nums)
    {
        // 当前覆盖的最远下标
        int curDistance = 0;
        // 下一步覆盖的最远距离下标
        int nextDistance = 0;
        // 最大步数
        int steps = 0;

        for (int i = 0; i < nums.size(); i++)
        {
            // 更新下一步覆盖的最远下标
            nextDistance = max(nextDistance, nums[i] + i);
            // 遇到当前的最大覆盖下标
            if (i == curDistance)
            {
                // 如果当前的最大覆盖下标还不是最后一个元素的下标
                // 就需要再走一步
                if (curDistance != nums.size() - 1)
                {
                    steps++;
                    curDistance = nextDistance;
                    // 如果下一步的最大覆盖下标已经可以到达最后一个元素就停止
                    if (nextDistance >= nums.size() - 1)
                    {
                        break;
                    }
                }
                // 如果是终点就停止
                else
                {
                    break;
                }
            }
        }
        return steps;
    }
};
复制代码

改进

不考虑移动后是否到达终点

class Solution
{
public:
    int jump(vector<int> &nums)
    {
        // 当前覆盖的最远下标
        int curDistance = 0;
        // 最大步数
        int steps = 0;
        // 下一步覆盖的最远下标
        int nextDistance = 0;

        // 这里下标 i < nums.size()-1
        for (int i = 0; i < nums.size() - 1; i++)
        {
            // 更新下一步的最远覆盖下标
            nextDistance = max(nextDistance, nums[i] + i);
            // 遇到当前覆盖的最远下标时
            if (i == curDistance)
            {
                // 更新当前覆盖的最远下标
                curDistance = nextDistance;
                steps++;
            }
        }
        return steps;
    }
};
复制代码

猜你喜欢

转载自juejin.im/post/7035826294520545287