DAY37:贪心算法(四)跳跃游戏+跳跃游戏Ⅱ

news2024/11/23 12:22:05

文章目录

    • 55.跳跃游戏
      • 思路
      • 完整版
      • 总结
    • 45.跳跃游戏Ⅱ
      • 思路
      • 完整版
        • 为什么next覆盖到了终点可以直接break,不用加上最后一步
        • 逻辑梳理
      • 总结

55.跳跃游戏

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标

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

判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 13 步到达最后一个下标。

示例 2:

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

提示:

  • 1 <= nums.length <= 3 * 104
  • 0 <= nums[i] <= 105

思路

游戏大致规则如下图。每一步代表着能跳跃的最大长度。能通过不同的步数组合,跳到最后一个下标就输出true。

在这里插入图片描述
本题直接看每个元素应该跳几步很难解出来,需要去看覆盖范围。如下图所示。

也就是说,不要管跳几步,不看具体是怎么跳的,只看每个数字的覆盖范围。如果是3,就覆盖后面三个数,如果是2,就覆盖后面两个数。

在这里插入图片描述

完整版

  • 在已有的覆盖范围内遍历每一个元素,得到新的可跳跃的步数,增加覆盖范围,取最大的覆盖范围
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int cover=0;
        if(nums.size()==1) return true;
        //此时是i<=cover而不是i<=nums.size(),因为是在覆盖范围内部遍历
        for(int i=0;i<=cover;i++){
            //找范围内最大的cover数值
            cover = max(i+nums[i],cover);
            if(cover>=nums.size()-1){
                return true;
            }
        }
        //如果遍历完了cover还没找到
        return false;
    }
};

这种思路还是比较难以理解的话,可以看下面的图进行对比。

在这里插入图片描述
由上图可知,我们不需要知道他的跳跃路径,只需要看cover内部,最大的覆盖范围就行了!

总结

这道题目关键点在于:不用拘泥于每次究竟跳几步,而是看覆盖范围覆盖范围内一定是可以跳过来的,不用管是怎么跳的

从这道题也可以看出来贪心并没有什么套路,只能多接触,没接触的话想不出来,接触之后下次就要考虑这种思维。

45.跳跃游戏Ⅱ

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

  • 本题解法也不太好想,最好结合视频课程和画图一起理解。

给定一个长度为 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

提示:

  • 1 <= nums.length <= 104
  • 0 <= nums[i] <= 1000
  • 题目保证可以到达 nums[n-1]

思路

本题和跳跃游戏的区别是,本题需要输出最少跳几步,才能跳到终点的位置。

此时也不能每一步都跳最大值,因为最少的情况并不一定是每一步都跳了当前的最大值

本题依然是用覆盖范围的思想,每跳一步,尽可能地增加覆盖范围只要覆盖范围覆盖了终点,说明用当前步数就可以跳到终点位置。

在这里插入图片描述

完整版

  • 本题的条件,也是i<=cover,没必要用i<=nums.size()
  • 但是本题多了一步next,也就是下一步的值,是记录cover内部遍历过的下一步的最大值
  • 注意next是记录的下一步能达到的最大的下标结果值,包括了数值很大但是本身很靠前的情况。
class Solution {
public:
    int jump(vector<int>& nums) {
        //如果数组长度只有1,那么就是0步
        if(nums.size()==1) return 0;
        int cover=0;
        //统计下一步的覆盖范围,是cover内的最大值
        int next=0;
        int result=0;
        //本题的条件,也是i<=cover,没必要用i<=nums.size()
        for(int i=0;i<=cover;i++){
            next=max(i+nums[i],next);//只记录遍历过的数字里,最大的下一步的下标值
            if(i==cover){//移动到了当前的终点
                if(i<nums.size()-1){//如果没到头,就再走一步
                    result++;
                    cover=next;//启动下一步覆盖范围,一旦覆盖到终点,立即break,因为result已经++了
                    if(cover>=nums.size()-1){
                    	break;
                    }
                }
                //如果到头了,也就是当前的cover已经到终点了
                else
                    break;
            }
        }
        return result;
    }
};

为什么next覆盖到了终点可以直接break,不用加上最后一步

本题的逻辑是,当达到cover的时候,result直接跳出循环。

例如输入[2,3,1,1,4],cover的时候遍历到nums[2]的时候,加上next已经满足条件,直接break出去,并没有对result再次进行++操作。

这是因为最开始的时候cover=0,而i也=0,也就是说最开始的时候已经累积一步了!由于我们把长度为1只有一个数字的情况单独放了,所以遍历到下面一定是长度>=2的,至少要走一步。相当于最开始已经累积一步了。

逻辑梳理

在这个算法中,每一次跳跃实际上都是在覆盖范围(cover)的边界上进行的,而不是在覆盖范围内部。

所以当我们第一次进入循环时,i等于cover(都是0),并且这时我们实际上已经做了第一次“跳跃”,也就是从起点跳到了能够覆盖的最远距离,因此result增加1。然后,每一次当i再次等于cover时,我们就会进行下一次跳跃,也就是从当前覆盖范围的边界跳到下一次能够到达的最远位置(也就是max(i+nums[i])

当遍历到cover的时候,如果cover已经覆盖到了数组的末尾,那么我们就直接跳出循环,因为这表示我们已经跳到了终点,没有必要再跳了。但是在跳出循环之前,我们已经把这次跳跃计入了result中,所以不会漏掉最后一次跳跃

总结

这道题比起跳跃游戏Ⅰ难了很多,本题关键在于,以最小的步数增加最大的覆盖范围,直到覆盖范围覆盖了终点,这个范围内最小步数一定可以跳到,不用管具体是怎么跳的,也不用纠结于一步究竟跳一个单位还是两个单位。

这也是一个贪心策略,我们试图在每次跳跃中到达能覆盖更远的位置。所以在每一轮循环中,我们尝试遍历当前的覆盖范围(cover)内的所有位置,并在这个范围内找到能够跳跃到的最远位置的下标,这个最远的距离我们保存在变量next中,将next与最后一个下标对比。

当数组长度大于1时,我们实际上是在循环开始时就已经“预先”计算了一次跳跃,所以当next超出范围,直接break,不会漏掉任何一次跳跃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/714925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

weui 密码二次检查校验

检验规则里rules[]增加: equalTo:需要匹配一致的字段名 我这第一个密码是&#xff1a;USR_PWD&#xff0c;第二个密码是&#xff1a;USR_PWD2,让第二个等于第一个就可以了&#xff1a; equalTo:USR_PWD 效果&#xff1a;

MIT 6.S081 教材第七章内容 -- 调度 --下

MIT 6.S081 教材第七章内容 -- 调度 -- 下 引言调度多路复用代码&#xff1a;上下文切换代码&#xff1a;调度代码&#xff1a;mycpu和myprocsleep与wakeup代码&#xff1a;sleep和wakeup代码&#xff1a;Pipes代码&#xff1a;wait, exit和kill真实世界练习 引言 MIT 6.S081 …

0基础学习VR全景平台篇 第54篇: 高级功能-皮肤

功能位置示意 一、本功能将用在哪里&#xff1f; 皮肤功能&#xff0c;摆脱传统VR全景展示样式&#xff0c;自行选择场景与全景分组的界面模板&#xff0c;从而与不同的应用行业风格相互适应&#xff0c;达到最贴切的展示效果。 是在各种风格的VR全景作品中&#xff0c;最快实…

C++ DAY5

1.全局变量&#xff0c;int monster 10000;定义英雄类hero&#xff0c;受保护的属性string name&#xff0c;int hp,int attck&#xff1b;公有的无参构造&#xff0c;有参构造&#xff0c;虚成员函数 void Atk(){monster-0;}&#xff0c;法师类继承自英雄类&#xff0c;私有属…

前端web入门-移动web-day09

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 空间转换 空间转换 – 平移 视距 perspective 空间 – 旋转 立体呈现 – transform-style 空间转换…

Docker学习笔记16

在生产环境中使用Docker&#xff0c;往往需要对数据进行持久化&#xff0c;或者需要在多个容器之间进行数据共享。 容器管理数据有两种方式&#xff1a; 1&#xff09;数据卷&#xff1a;容器内数据直接映射到本地主机环境&#xff1b; 2&#xff09;数据卷容器&#xff1a;…

服务器远程管理工具Xshell安装及使用,传输文件工具安装及使用

两个软件 Xshell 双击输入用户名和密码 也可以通过密钥的方式 怎么生成密钥还没做过 Xftp 一边主机一边服务器&#xff0c;相互拖动就行了

【C#】并行编程实战:实现数据并行(3)

本章继续学习实现数据并行&#xff0c;本文主要介绍取消循环。 本教程对应学习工程&#xff1a;魔术师Dix / HandsOnParallelProgramming GitCode 4、取消循环 在顺序循环中&#xff0c;可以使用 break 来跳出循环&#xff0c;而在并行循环的情况下&#xff0c;由于他…

Unity协程

unity提供了一种类似“多段代码并行执行”的功能&#xff0c;即协程。 我们在定义一个协程的时候&#xff0c;需要遵循类似这样的语法 IEnumerator&#xff08;枚举器接口&#xff09; namespace System.Collections {public interface IEnumerator{object Current { get; }/…

卷积神经网络--猫狗系列【VGG16】

数据集&#xff1a;【文末】 ​ 数据集预处理 定义读取数据辅助类&#xff08;继承torch.utils.data.Dataset&#xff09; import osimport PILimport torchimport torchvisionimport matplotlib.pyplot as pltimport torch.utils.dataimport PIL.Image # 数据集路径train_p…

哈希桶的增删查改简单实现

个人简单笔记。 目录 闭散列 开散列 插入 删除 查找 改变 什么是哈希桶呢&#xff1f;这是一个解决哈希数据结构的一种解决方法&#xff0c;在STL中的unorder_map与unorder_set的底层结构就是使用它来实现的。 闭散列 首先我们知道&#xff0c;哈希映射表是依据数组下…

CSS画特殊边框

例如如图所示边框 .card-middle {width: 672px;height: 486px;border: 1px solid #5fadec;border-radius: 5px;position: relative; }.card-middle::before {content: ;position: absolute;top: -4px;left: -4px;width: 680px;height: 448px;border: 25px solid transparent;b…

【Python】PIL.Image转QPixmap后运行异常的个人解决方法

问题场景&#xff1a; PIL.Image图片&#xff0c;直接调用PIL.Image.toqpixmap()转成QPixmap后&#xff0c;不会立即报错&#xff0c;   但后续使用该QPixmap时(包括但不仅限于使用QLabel.setPximap()、QPixmap.save())将立即出现异常 不知道是我关键词不对&#xff0c;还是只…

【数据结构与算法】文学语言助手(C\C++)

实践要求 1. 问题描述 文学研究人员需要统计某篇英文小说中某些形容词的出现次数和位置。试写一个实现这一目标的文字统计系统&#xff0c;称为"文学研究助手"。 2. 基本要求 英文小说存于文本文件中。待统计的词汇集合要一次输入完毕&#xff0c;即统计工作必需在…

linux常用命令介绍 06 篇——Linux查看目录层级结构以及创建不同情况的层级目录

linux常用命令介绍 06 篇——Linux查看目录层级结构以及创建不同情况的层级目录 1. 前言1.1 Linux常用命令其他篇1.2 关于tree简介 2. 安装并使用 tree2.1 安装tree2.1.1 方式1&#xff1a;yum安装2.1.2 方式2&#xff1a;下载安装包安装2.1.2.1 下载安装包2.1.2.2 解压安装2.1…

transformer入坑指南

*免责声明: 1\此方法仅提供参考 2\搬了其他博主的操作方法,以贴上路径. 3* 场景一: Attention is all you need 场景二: VIT 场景三: Swin v1 场景四: Swin v2 场景五: SETR 场景六: TransUNet 场景七: SegFormer 场景八: PVT 场景九: Segmeter … 场景一:Attention…

Spring Boot 中的 Spring Cloud Ribbon:什么是它,原理及如何使用

Spring Boot 中的 Spring Cloud Ribbon&#xff1a;什么是它&#xff0c;原理及如何使用 在分布式系统中&#xff0c;服务之间的通信是非常重要的。在大型的分布式系统中&#xff0c;有许多服务需要相互通信&#xff0c;而这些服务可能会部署在多个服务器上。为了实现服务之间…

超详细Redis入门教程——Redis分布式系统

前言 本文小新为大家带来 Redis分布式系统 相关知识&#xff0c;具体内容包括数据分区算法&#xff08;包括&#xff1a;顺序分区&#xff0c;哈希分区&#xff09;&#xff0c;系统搭建与运行&#xff08;包括&#xff1a;系统搭建&#xff0c;系统启动与关闭&#xff09;&…

把 OpenGrok search 上的Android 开源代码扒下来

1、下载工具 wget &#xff08;window10版本&#xff09;以及配置环境变量 工具我会上传到本篇博客的“代码包”区域&#xff0c;可以自行下载&#xff01; 当然如果可以访问如下链接的话&#xff0c;也可以在这个地址自行下载一个比较新的版本即可&#xff01;GNU Wget 1.21.…

Web服务器群集:LVS+Keepalived高可用群集

目录 一、理论 1.Keepalived 2.VRRP协议&#xff08;虚拟路由冗余协议&#xff09; 3.部署LVSKeepalived 高可用群集 二、实验 1.LVSKeepalived 高可用群集 三、问题 1.备服务器网卡启动报错 四、总结 一、理论 1.Keepalived &#xff08;1&#xff09;简介 Keepal…