当前位置:   article > 正文

leetCode 45.跳跃游戏 II 贪心算法_2.给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。每个元素 num

2.给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。每个元素 num

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

给定一个长度为 n 的 0 索引整数数组 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++代码如下:

  1. class Solution {
  2. public:
  3. // 贪心算法 时间复杂度: O(n) 空间复杂度: O(1)
  4. int jump(vector<int>& nums) {
  5. if (nums.size() == 1) return 0;
  6. int cur = 0;// 当前覆盖最远距离下标
  7. int next = 0;// 下一步覆盖最远距离下标
  8. int result = 0;// 记录走的最大步数
  9. for(int i=0;i<nums.size()-1;i++) {
  10. next=max(i+nums[i],next);// 更新下一步覆盖最远距离下标
  11. if(i == cur) {// 遇到当前覆盖最远距离下标
  12. if(cur != nums.size()-1) {
  13. result++; // 需要走下一步
  14. cur = next;// 更新当前覆盖最远距离下标(相当于加油了)
  15. if(cur >= nums.size()-1 ) break; // 当前覆盖最远距到达集合终点,不用做result++操作了,直接结束
  16. }else break;
  17. }
  18. }
  19. return result;
  20. }
  21. };

来自代码随想录版本一:

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

 来自代码随想录版本二:

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

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

参考和推荐文章、视频:

 代码随想录 (programmercarl.com)

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/390557
推荐阅读
相关标签
  

闽ICP备14008679号