Studying-代码随想录训练营day29| 134. 加油站、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列

第29天,贪心part03,快过半了(ง •_•)ง💪,编程语言:C++

目录

134.加油站

135. 分发糖果

860.柠檬水找零

406.根据身高重建队列


134.加油站

文档讲解:代码随想录加油站

视频讲解:手撕加油站

题目:

学习:本题其实很容易发现gas数组和cost数组的差,就是该站点结余的油量,我们在移动过程中理应让油量始终保持为正。因此本题的思考逻辑就是从某个站点出发,如果油量小于0则说明该点不能环路行驶一圈,反则则可以。

解法一:暴力解法,暴力遍历每个节点环行一周的结果。(力扣超时)

注意:for循环适合模拟从头到尾的遍历,而while循环适合模拟环形遍历,因此对于本题的场景需要使用while进行环行循环要十分注意。

//时间复杂度O(n^2)
//空间复杂度O(1)
class Solution {
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {for (int i = 0; i < cost.size(); i++) {int rest = gas[i] - cost[i]; // 记录剩余油量int index = (i + 1) % cost.size();while (rest > 0 && index != i) { // 模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)rest += gas[index] - cost[index];index = (index + 1) % cost.size();}// 如果以i为起点跑一圈,剩余油量>=0,返回该起始位置if (rest >= 0 && index == i) return i;}return -1;}
};

解法二:贪心

贪心策略为:首先只有在总油量减去总消耗大于等于0的时候,才说明可以跑完一圈。其次我们在环行的过程中,还需要保持剩油量是正的,才能够继续行驶下去。因此我们可以 i 从0开始累加每个站点的剩油量(gas[i] - cost[i]),一旦累加和小于零,则说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油(一定不会说从中间开始某个点不会断油,因为如果是那样的话后半部分为正,那前半部分一定为负,也会使得满足剩油量为负的条件,跳到i+1),那么起始位置从i+1算起,再从0计算剩油量。

那么局部最优:当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。全局最优:找到可以跑一圈的起始位置

代码:

//时间复杂度O(n)
//空间复杂度O(1)
class Solution {
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {//贪心,局部最优找到累加为正的地方int count = 0; //计算总和,总和小于0说明无法环路一周int idcount = 0; //计算当前i往后的总和,该总和小于0说明不能从i出发int index = 0; //找到正确的出发下标for(int i = 0; i < gas.size(); i++) {int rest = gas[i] - cost[i];count += rest;idcount += rest;if(idcount < 0) { // 当前累加rest[i]和 curSum一旦小于0idcount = 0;  // idcount从0开始计算index = i + 1;  //起始位置更新为i+1}}if(count < 0) return -1;return index;}
};

135. 分发糖果

文档讲解:代码随想录分发糖果

视频讲解:手撕分发糖果

题目:

学习:本题属于贪心算法中两个维度的问题,也就是需要两次贪心分别处理两种情况。本题中我们对于一个孩子来说,即要考虑他的左边和他的大小关系,又要考虑他的右边和他的大小关系,这就是我们要处理的两个问题。对于这种情况而言,我们需要将这两个问题分开解决,先考虑每个孩子右边比自身大的情况,再考虑每个孩子左边比自身大的情况,不能同时考虑,否则就会顾此失彼。

首先考虑右边孩子评分大的情况,从前向后遍历。此时的局部最优为:只要右边评分比左边大,右边的孩子就多一个糖果。全局最优为:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果。

接着我们再确定左边孩子评分大的情况,从后往前遍历。此时的局部最优就为:只要左边评分比右边大,左边的孩子就多一个糖果。全局最优为:相邻的孩子中,评分高的左孩子获得比右边孩子更多的糖果。(这个地方要注意,再更新评分更高的孩子的时候,我们要判断此时更新的值和原本的值谁更大,因为原本的值是保证了他和他左边孩子的关系,因为谁更大取谁,这样就能够同时保证左右孩子的关系了。

代码:

//时间复杂度O(n)
//空间复杂度O(n)
class Solution {
public:int candy(vector<int>& ratings) {//两次贪心vector<int> candys(ratings.size(), 1); //初始化先给每个小孩一个糖果//第一次贪心,从左向右,先遍历右孩子比左孩子大的情况,局部最优:右孩子比左孩子大就多一个糖果for(int i = 1; i < ratings.size(); i++) {if(ratings[i] > ratings[i - 1]) {candys[i] = candys[i - 1] + 1;}}//第二次贪心,从右向左,遍历左孩子比右孩子大的情况,局部最优:左孩子比右孩子大就多一个糖果for(int i = ratings.size() - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) {//这里要注意要去当前值和右孩子加1之间的最大值,这样才能保证该点同时大于左右孩子。candys[i] = max(candys[i], candys[i + 1] + 1); }}//求和int result = 0;for(int i = 0; i < candys.size(); i++) {result += candys[i];}return result;}
};

860.柠檬水找零

文本讲解:代码随想录柠檬水找零

视频讲解:手撕柠檬水找零

题目:

学习:本题看起来题干很多很复杂,但实际上就是每位顾客花5美元买柠檬水,但这个过程中会出现三种情况分别是:1.顾客给了5美元,不需要找钱;2.顾客给了10美元,需要找5美元给顾客;3.顾客给了20美元,需要找15美元给顾客。针对这三种情况我们可以逐个分析。 

1.顾客给了5美元:对于这种情况,我们不需要找钱的同时,我们手里还多了一张5美元。

2.顾客给了10美元,需要找5美元:对于这种情况,需要我们手头上有至少一张5美元,否则我们就不能正确找零返回false。如果我们手头上有至少一张5美元,则我们减少一张5美元,多一张10美元。

3.顾客给了20美元,需要找15美元:对于这种情况,就是需要我们进行贪心算法的时候了,因为对于我们来说5美元既可以给10美元的顾客找钱,又可以给20美元的顾客找钱。因此我们在给20美元的顾客找钱的时候应优先消耗美元10,保留更加万能的5美元,这样才能更好的进行正确的找零。因此有三种情况:1.手头上有10美元,5美元,则减少一张10美元,一张5美元;2.手头上美元10美元,但5美元大于3张,则减少3张5美元;3.手头上凑不出15美元的数(注意两张10美元不行)返回false。

代码:根据以上三种情况,则可编写代码

//时间复杂度O(n)
//空间复杂度O(1)
class Solution {
public:bool lemonadeChange(vector<int>& bills) {//记录手头上5美元和10美元的数量,20美元的不需要记录,因为20没有不能用于找钱int count5 = 0;int count10 = 0;for(int i = 0; i < bills.size(); i++) {//分别处理收到三种钱的情况if(bills[i] == 5) {count5++;}if(bills[i] == 10) {if(count5 == 0) {return false;}count5--;count10++;}//第三种情况需要进行贪心//贪心策略:如果有10元钞票优先找10元钞票,因为5元钞票比10元钞票更万能if(bills[i] == 20) {if(count10 > 0 && count5 > 0) {count10--;count5--;}else if(count5 >= 3) {count5 -= 3;}else {return false;}}}return true;}
};

406.根据身高重建队列

文档讲解:代码随想录根据身高重建队列

视频讲解:手撕根据身高重建队列

题目:

学习:本题与分发糖果相同,同样都是两维问题,我们需要分别考虑身高和前面身高大于等于的人的数量这两个因素。不能两个维度一起考虑,一定会出现顾此失彼的情况。

本题中如果我们需要对数组先进行排序,来解决一个维度上的问题。如果我们选择对k(身高大于等于的数量)进行排序,会发现最后得到的数组会发现k的排列不符合条件,身高也不符合条件,两个维度都没办法确定下来(这是因为会存在部分身高很高,因此k为0的干扰)。

因此本题我们需要先对身高进行排序,身高从高到低进行排序,这样也会有个好处,排序之后,如果后面的位置出现问题需要前插,也不会影响前面的数的排序,因为后面的数一定比前面的数小,不会影响到k值。

因此本题的贪心就是:局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性;全局最优:最后都做完插入操作,整个队列满足题目队列属性。

代码:

//时间复杂度O(nlogn + n^2)
//空间复杂度O(n)
class Solution {
public:static bool camp(vector<int>&a, vector<int>&b) {//身高从大到小排列,便于进行插入处理if(a[0] != b[0]) {return a[0] > b[0];}else { //如果身高一样,让其前面身高少的排前面return a[1] < b[1];}}vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {//对数组进行排序,让身高高的先排前面,这样我们就能依据前面身高的数量,来插入每一个数sort(people.begin(), people.end(), camp);//贪心策略,遍历数组,优先按照身高高的people的k来进行插入,这样也就不用担心后续身高矮的插入造成影响vector<vector<int>> queue; //这里不能初始化数组的大小,因为后续要采用插入进行操作for(int i = 0; i < people.size(); i++) {int index = people[i][1]; //确定要插入的位置queue.insert(queue.begin() + people[i][1], people[i]);}return queue;}
};

本题中存在一个问题,使用vector是非常费时的,C++中vector(可以理解是一个动态数组,底层是普通数组实现的)如果插入元素大于预先普通数组大小,vector底部会有一个扩容的操作,即申请两倍于原先普通数组的大小,然后把数据拷贝到另一个更大的数组上。所以使用vector(动态数组)来insert,是费时的,插入再拷贝的话,单纯一个插入的操作就是O(n^2)了,甚至可能拷贝好几次,就不止O(n^2)了。

代码:因此本题可以采用list类来保存数组,虽然时间复杂度没变,但实际效率是增加了的。

class Solution {
public:// 身高从大到小排(身高相同k小的站前面)static bool cmp(const vector<int>& a, const vector<int>& b) {if (a[0] == b[0]) return a[1] < b[1];return a[0] > b[0];}vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {sort (people.begin(), people.end(), cmp);list<vector<int>> que; // list底层是链表实现,插入效率比vector高的多for (int i = 0; i < people.size(); i++) {int position = people[i][1]; // 插入到下标为position的位置std::list<vector<int>>::iterator it = que.begin();while (position--) { // 寻找在插入位置it++;}que.insert(it, people[i]);}return vector<vector<int>>(que.begin(), que.end());}
};

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

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

相关文章

《梦醒蝶飞:释放Excel函数与公式的力量》8.3 COUNTBLANK函数

8.3 COUNTBLANK函数 在数据处理和分析中&#xff0c;我们经常需要识别和统计数据集中的空白单元格。COUNTBLANK函数是Excel中用于统计某个范围内空白单元格数量的强大工具。 8.3.1 函数简介 COUNTBLANK函数用于统计指定范围内的空白单元格数量。这在数据清洗、数据完整性检查…

MySQL之备份与恢复(四)

备份与恢复 存储引擎和一致性 3.复制 从备库中备份最大的好处是可以不干扰主库&#xff0c;避免在主库上增加额外的负载。这是一个建立备库的好理由&#xff0c;即使不需要用它做负载均衡或高可用。如果钱是个问题&#xff0c;也可以把备份用的备库用于其他用户&#xff0c;…

Matlab/simulink三段式电流保护

电流1段仿真波形如下所示 电流2段仿真波形如下所示 电流3段仿真波形如下所示

Centos7安装Minio笔记

一、Minio概述 Minio是一款开源的对象存储服务器&#xff0c;可以运行在多种操作系统上&#xff0c;包括Linux、Windows和MacOS等。提供一种简单、可扩展、高可用的对象存储解决方案&#xff0c;支持多种数据格式&#xff0c;包括对象、块和文件等。Minio是一款强大、灵活、可…

WCCI 2024第三弹:忍者表演惊艳全场,盛大晚宴不容错过

WCCI 2024第三弹&#xff1a;忍者表演惊艳全场&#xff0c;盛大晚宴不容错过&#xff01; 会议之眼 快讯 会议介绍 IEEE WCCI&#xff08;World Congress on Computational Intelligence&#xff09;2024&#xff0c;即2024年IEEE世界计算智能大会&#xff0c;于6月30日至7月…

【前端知识】一篇速成 建议收藏

HTML基础概念 正式敲代码之前呢,我们先来看几个概念: 0 静态网页和动态网页 静态网页: 页面的内容和显示效果就基本上不会发生变化了--除非你修改页面代码。 动态网页: 页面代码虽然没有变&#xff0c;但是显示的内容却是可以随着时间、环境或者数据库操作的结果而发生改变的…

【Qt知识】window frame 对窗口坐标的影响

在Qt中&#xff0c;窗口框架&#xff08;Window Frame&#xff09;对Widget的尺寸计算和坐标定位有着直接的影响&#xff0c;这主要是因为窗口框架本身占据了一定的空间&#xff0c;包括标题栏、最小化/最大化/关闭按钮以及边框。这部分额外的空间在不同的应用场景下需要被考虑…

windows非白名单exe监控并杀死

需求&#xff1a;孩子在家用电脑上网课&#xff0c;总是悄悄打开游戏或视频软件 方案&#xff1a;指定白名单exe&#xff0c;打开非白名单的就自动被杀死&#xff0c;并记录日志供查看 不知道是否还有更好的结果方案&#xff1f; import psutil import time import logging#…

第二十条:与抽象类相比,优先选择接口

要定义多种实现的类型&#xff1a;JAVA有两种机制&#xff1a;接口和抽象类。这两种机制都支持为某些实例方法提供实现&#xff0c;但二者有个重要的区别&#xff1a;要实现由抽象类定义的类型&#xff0c;这个类必须是抽象类的子类。因为Java只允许单继承&#xff0c;对抽象类…

使用SSE实现echarts数据实时更新

区别 SSE 和 WebSocket 原理和实现方式的区别 SSE( Server-Sent Events) SSE 是基于传统的 HTTP 协议实现的&#xff0c;采用了长轮询&#xff08;long-polling&#xff09;机制。客户端通过向服务器发送一个 HTTP 请求&#xff0c;服务器保持连接打开并周期性地向客户端发送…

内网穿透--利用everything实现目录映射

免责声明:本文仅做技术交流与学习... 目录 来源文章 frp下载网址 为了隐藏: 演示: 1-靶机的everything开启http服务 2-Linux服务器: 3-靶机windows: 4-最后访问: 来源文章 渗透测试技巧|Everything的利用 frp下载网址 Release v0.58.1 fatedier/frp GitHub 为了隐…

协程调度模块

什么是协程和协程调度&#xff1f; 基本概念 协程 协程是一种比线程更轻量级的并发编程结构&#xff0c;它允许在函数执行过程中暂停和恢复执行状态&#xff0c;从而实现非阻塞式编程。协程又被称为用户级线程&#xff0c;这是由于协程包括上下文切换在内的全部执行逻辑都是…

WAIC热点聚焦|具身智能简介:AI新浪潮的领跑者

WAIC热点聚焦|具身智能简介&#xff1a;AI新浪潮的领跑者 引言 随着"具身智能"&#xff08;Embodied Intelligence&#xff09;的火热讨论&#xff0c;2024年标志着人机交互新时代的开启。在大模型技术的推动下&#xff0c;机器人响应语音指令成为现实&#xff0c;…

Linux Rsyslog+LogAnalyzer+MariaDB部署日志服务器

文章目录 Linux RsyslogLogAnalyzerMariaDB部署日志服务器1 环境准备1.1 服务器端安装LAMP环境1.2 服务启动并加入开机启动1.2.1 Apache1.2.2 MariaDB1.2.3 Php 2 Rsyslog服务端安装及配置2.1 安装Rsyslog及Rsyslog连接MySQL的模块2.2 导入rsyslog-mysql数据库文件2.3 查看刚导…

深入浅出:npm常用命令详解与实战

theme: smartblue npm是什么 npm&#xff08;Node Package Manager&#xff09;是Node.js平台的默认包管理器&#xff0c;它让JavaScript开发者能够轻松地共享、管理和使用彼此编写的代码模块。npm不仅仅是一个安装工具&#xff0c;它还是一个全面的生态系统&#xff0c;用于发…

【YOLOv5/v7改进系列】替换损失函数为WIOU、CIOU、GIOU、SIOU、DIOU、EIOU、Focal C/G/S/D/EIOU等

一、导言 在目标检测任务中&#xff0c;损失函数的主要作用是衡量模型预测的边界框&#xff08;bounding boxes&#xff09;与真实边界框之间的匹配程度&#xff0c;并指导模型学习如何更精确地定位和分类目标。损失函数通常由两部分构成&#xff1a;分类损失&#xff08;用于…

RabbitMQ入门教程(精细版二带图)

目录 六 RabbitMQ工作模式 6.1Hello World简单模式 6.1.1 什么是简单模式 6.1.2 RabbitMQ管理界面操作 6.1.3 生产者代码 6.1.4 消费者代码 6.2 Work queues工作队列模式 6.2.1 什么是工作队列模式 6.2.2 RabbitMQ管理界面操作 6.2.3 生产者代码 6.2.4 消费者代码 …

【最新】App Inventor 2 学习平台和AI2伴侣使用

1、AppInventor2服务器&#xff1a; 官方服务器&#xff1a;http://ai2.appinventor.edu/ 官方备用服务器&#xff1a;http://code.appinventor.mit.edu/ 国内同步更新服务器&#xff1a;https://www.fun123.cn 国内访问速度很快&#xff0c;很稳定&#xff0c;文档是中文的…

偏微分方程笔记(驻定与非驻定问题)

椭圆方程可以看成抛物方程 t → ∞ t\rightarrow\infty t→∞的情况。 抛物&#xff1a; 双曲&#xff1a;

DolphinDB 蝉联 Gartner 中国实时数据管理代表厂商

报&#xff01;DolphinDB 又上榜啦&#xff01;&#xff01;&#xff01; 上月&#xff0c;全球知名信息技术研究公司 Gartner 发布了 Hype Cycle for Data, Analytics and AI in China, 2024 报告&#xff0c;以技术成熟度曲线&#xff08;Hype Cycle&#xff09;和优先级矩阵…