leetCode 45.跳跃游戏 II 贪心算法

45. 跳跃游戏 II - 力扣(LeetCode)

给定一个长度为 n0 索引 整数数组 nums 。初始位置为nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意**nums[i + j]**处:

  • 0 <= j <= nums[i]
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达nums[n - 1]

示例 1:

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

示例 2:

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

>>思路和分析

本题相对于leetCode 55.跳跃游戏 贪心算法 难度增加了 ,但是思路还是相似的,还是要看最大的覆盖范围

贪心思路:****(O_O)?思考:计算最少步数,请问什么时候步数才一定要加一呢?

  • **① 局部最优:**当前可移动距离尽可能多走,如果还没到终点,步数再加一
  • **② 整体最优:**一步尽可能多走,从而达到最少步数

真正解题的时候,要从覆盖范围出发,不管怎么跳**,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,覆盖范围一旦覆盖了终点,得到的就是最少步数!**

需要统计两个覆盖范围,当前这一步的最大覆盖和下一步最大覆盖!

如果移动下标达到了当前这一步的最大覆盖最远距离了,还没有到终点的话,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点

图中覆盖范围的意义在于,只要红色的区域,最多两步一定可以到!(不用管具体怎么跳,反正一定可以跳到)

C++代码如下:

cpp 复制代码
class Solution {
public:
    // 贪心算法 时间复杂度: O(n) 空间复杂度: O(1)
    int jump(vector<int>& nums) {
        if (nums.size() == 1) return 0;
        int cur = 0;// 当前覆盖最远距离下标
        int next = 0;// 下一步覆盖最远距离下标
        int result = 0;// 记录走的最大步数
        for(int i=0;i<nums.size()-1;i++) {
            next=max(i+nums[i],next);// 更新下一步覆盖最远距离下标
            if(i == cur) {// 遇到当前覆盖最远距离下标
                if(cur != nums.size()-1) {
                    result++; // 需要走下一步
                    cur = next;// 更新当前覆盖最远距离下标(相当于加油了)
                    if(cur >= nums.size()-1 ) break; // 当前覆盖最远距到达集合终点,不用做result++操作了,直接结束
                }else break;
            }
        }
        return result;
    }
};

来自代码随想录版本一:

cpp 复制代码
// 版本一
class Solution {
public:
    int jump(vector<int>& nums) {
        if (nums.size() == 1) return 0;
        int curDistance = 0;    // 当前覆盖最远距离下标
        int ans = 0;            // 记录走的最大步数
        int nextDistance = 0;   // 下一步覆盖最远距离下标
        for (int i = 0; i < nums.size(); i++) {
            nextDistance = max(nums[i] + i, nextDistance);  // 更新下一步覆盖最远距离下标
            if (i == curDistance) {                         // 遇到当前覆盖最远距离下标
                ans++;                                  // 需要走下一步
                curDistance = nextDistance;             // 更新当前覆盖最远距离下标(相当于加油了)
                if (nextDistance >= nums.size() - 1) break;  // 当前覆盖最远距到达集合终点,不用做ans++操作了,直接结束
            }
        }
        return ans;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

来自代码随想录版本二:

cpp 复制代码
// 版本二
class Solution {
public:
    int jump(vector<int>& nums) {
        int curDistance = 0;    // 当前覆盖的最远距离下标
        int ans = 0;            // 记录走的最大步数
        int nextDistance = 0;   // 下一步覆盖的最远距离下标
        for (int i = 0; i < nums.size() - 1; i++) { // 注意这里是小于nums.size() - 1,这是关键所在
            nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖的最远距离下标
            if (i == curDistance) {                 // 遇到当前覆盖的最远距离下标
                curDistance = nextDistance;         // 更新当前覆盖的最远距离下标
                ans++;
            }
        }
        return ans;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

理解本题的关键在于:以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点,这个范围内最少步数一定可以跳到,不用管具体是怎么跳的,不纠结于一步究竟跳一个单位还是两个单位。

参考和推荐文章、视频:

代码随想录 (programmercarl.com)

贪心算法,最少跳几步还得看覆盖范围 | LeetCode: 45.跳跃游戏II_哔哩哔哩_bilibili

相关推荐
九圣残炎15 分钟前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
~yY…s<#>2 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
linsa_pursuer3 小时前
快乐数算法
算法·leetcode·职场和发展
XuanRanDev3 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
代码猪猪傻瓜coding3 小时前
力扣1 两数之和
数据结构·算法·leetcode
南宫生4 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
passer__jw7676 小时前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode
星沁城7 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
一直学习永不止步8 小时前
LeetCode题练习与总结:赎金信--383
java·数据结构·算法·leetcode·字符串·哈希表·计数
劲夫学编程11 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展