代码随想录打卡Day29

ops/2024/10/22 16:21:31/

今天的题目尊嘟好难…除了第三题没看视频,其他的题目都是看了视频才做出来的。二刷等我。

134. 加油站

感觉这道题和之前的53. 最大子序和有点像,最大子序和是一旦当前总和为负数则立即抛弃当前的总和,从下个位置重新开始计算,而这道题是一旦遇到当前剩余的燃油小于0,则立马抛弃当前的燃油总和,以下个位置为新起点,当然这道题还需要计算遍历过的所有节点的燃油与损耗之差,万一循环结束current_sum>=0,但是total_sum<0也是不行的,所以在循环结束以后并不是判断current_sum是否大于0,因为有可能出现从0出发到不了第i个节点,从第i + 1个节点遍历到结束时current_sum >= 0,但是剩下的燃油+i节点前面的燃油坚持不到第i个节点的情况,综上,在循环结束以后应该判断total_sum是否大于等于0。

class Solution {
public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int result = 0;  //记录起始位置int current_sum = 0;  //到达某个站点后剩余的油量int total_sum = 0;   //记录所有能得到的油与消耗量之间的差值for(int i = 0; i < gas.size(); i++){current_sum += (gas[i] - cost[i]);  //执行完这条语句后车子已经到达第i + 1个站点了total_sum += (gas[i] - cost[i]);if(current_sum < 0){result = i + 1;current_sum = 0;}    }if(total_sum < 0) return -1; //已经遍历到末尾了,不可能跑一圈return result;}
};

135. 分发糖果

这道题我思路想到了,先从左往右遍历,处理一遍,再从后往前遍历一遍,再处理一遍,但是我在一些代码细节上没有想清楚,所以老是写不对,就很气。。。首先第一个代码细节是明确两次遍历的处理对象是谁,第一次从左往右遍历应该处理左边的值还是右边的值呢?我这里处理的是右边的值,代码是这么写的

//从左往右遍历(右边比左边大的情况)
for(int i = 1; i < ratings.size(); i++){if(ratings[i] > ratings[i - 1])v[i] = v[i - 1] + 1;
}

第二次遍历从右往左,由于前面遍历处理的是右值,反过来遍历的时候就必须处理左值,为什么?因为如果倒过来遍历还是处理右值的话,相当于做无用功,上一次遍历的时候已经对右值赋值过了,没有必要再用一次循环。处理左值的代码我是这么写的

//从右往左遍历(左边比右边大的情况)
for(int i = ratings.size() - 1; i > 0; i--){if(ratings[i] < ratings[i - 1])v[i - 1] = max(v[i] + 1, v[i - 1]);                
}

第二个细节就是第二次遍历的时候的赋值操作,并不是简单地在旁边的较小值的糖果数上加1就完事了,有可能在第一次遍历的时候已经满足大小关系了,第二遍再处理一遍的话会导致重复处理,糖果一定会多发,所以一定要取赋值过后与之前的值之间的较大值。
这是完整的代码

class Solution {
public:int candy(vector<int>& ratings) {vector<int> v(ratings.size(), 1);//从左往右遍历(右边比左边大的情况)for(int i = 1; i < ratings.size(); i++){if(ratings[i] > ratings[i - 1])v[i] = v[i - 1] + 1;}//从右往左遍历(左边比右边大的情况)for(int i = ratings.size() - 1; i > 0; i--){if(ratings[i] < ratings[i - 1])v[i - 1] = max(v[i] + 1, v[i - 1]);                }return accumulate(v.begin(), v.end(), 0);}
};

860.柠檬水找零

这个比较简单,收5块钱不找零,收10块钱只能找5块的零,收20块的优先用10+5找零,其次再用5+5+5找零,按照这个规则去遍历数组,在钞票数够用的情况下一定可以找零,return true,如果出现钞票不够的情况直接return false。

class Solution {
public:map<int, int> money;bool lemonadeChange(vector<int>& bills) {for(int i = 0; i < bills.size(); i++){if(bills[i] == 5)money[5]++;else if(bills[i] == 10){  if(money[5] == 0) //必须要有5元零钱return false;money[5]--;money[10]++;}else{if(money[5] == 0 || (money[10] * 10 + money[5] * 5 < 15)) //找不起钱return false;if(money[10] > 0){money[10]--;money[5]--;}else money[5] -= 3;}}return true;}
};

406.根据身高重建队列

说是说这个题目和分发糖果的思路很像,但是我还是做不出来┭┮﹏┭┮被自己菜哭了。这道题有两个维度,一个是身高h,一个是前面比本人高的人数k,这道题并不能先选择任意一个维度进行排序,因为先按照k排序过后得到的数组依旧没什么逻辑性,很混乱,但是按照身高降序排列的话能得到一些比较好的性质,那就是后面的元素插到前面时,该元素前面的元素的相对位置无需变动,因为从后面插进来的人身高一定会比前面的人矮,并不会影响前面的人的k值,这个性质就非常好。
这道题的原理想清楚以后还没有那么容易写出来,这个题目还比较考验C++基本功,需要对vector<vector>自定义排序规则,首先按身高进行降序排列,身高相同的则k值小的排前面。第二个就是要将元素插入到指定位置,其余元素相对位置不变,vector并没有现成的函数可以调用,所以要自己手搓一个,这里主要还是用swap函数来实现,当某个元素需要插入到前面时,就将该元素与前一个元素交换位置,如此循环,直到该元素被交换到指定位置。

class Solution {
public:static bool compareVectors(const std::vector<int>& a, const std::vector<int>& b) {  // 按照身高降序排列,若身高相同则k值小的靠前if(a[0] > b[0]) return true;else if(a[0] < b[0]) return false;else return a[1] < b[1];} vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {sort(people.begin(), people.end(), compareVectors);for(int i = 0; i < people.size(); i++){int j = i;int target = people[i][1];while(j > target){iter_swap(people.begin() + j, people.begin() + j - 1);j--;}}return people;}
};

好难啊。。今天这个博客是我写的篇幅最大的博客之一了。


http://www.ppmy.cn/ops/112831.html

相关文章

保护您的企业免受网络犯罪分子侵害的四个技巧

在这个日益数字化的时代&#xff0c;小型企业越来越容易受到网络犯罪的威胁。网络犯罪分子不断调整策略&#xff0c;并使用人工智能来推动攻击。随着技术的进步&#xff0c;您的敏感数据面临的风险也在增加。 风险的不断增大意味着&#xff0c;做好基本工作比以往任何时候都更…

04_Python数据类型_列表

Python的基础数据类型 数值类型&#xff1a;整数、浮点数、复数、布尔字符串容器类型&#xff1a;列表、元祖、字典、集合 列表 列表&#xff08;List&#xff09;是一种非常灵活的数据类型&#xff0c;它可以用来存储一系列的元素。容器类型&#xff0c;能够存储多个元素的…

MybatisPlus的一点了解

1.MybatisPlus使用&#xff1a; &#xff08;1&#xff09;Serializable id 这种参数要怎么传入值&#xff0c;对应的底层调用和数据库表格命名和实体类映射之间有什么关系 在 Java 中&#xff0c;Serializable 是一个标记接口&#xff0c;它表示一个类的实例可以被序列化&am…

0918作业

一、整理 1&#xff09;ls:查看文件信息 2&#xff09;passwd&#xff1a;修改密码 3&#xff09;cd&#xff1a;切换目录 4&#xff09;touch&#xff1a;创建文件 5&#xff09;mkdir&#xff1a;创建文件夹 6&#xff09;cp&#xff1a;拷贝文件 7&#xff09;mv&#xff1…

文件操作

1.文件的打开和关闭 文件在读写之前应该先打开文件&#xff0c;在使用结束之后应该关闭文件。 在编写程序的时候&#xff0c;在打开文件的同时&#xff0c;都会返回一个FILE*的指针变量指向该文件&#xff0c;也相当于建立了指针和文件的关系。ANSI C规定使用fopen函数来打开文…

软考中级软件设计师——存储系统

软考中级软件设计师——存储系统 存储系统&#xff08;层次结构&#xff09;存储系统分类高速缓存CacheCache组成Cache的三种地址映像Cache的性能分析 主存的扩展位扩展和字扩展主存的编址虚拟存储器磁盘存储器 存储系统&#xff08;层次结构&#xff09; 核心&#xff1a;在存…

AI问答-Vue实例属性/实例方法:$refs、$emit、$attrs、$props、$data...

一、本文简介 在Vue.js中&#xff0c;$ 符号通常用于表示Vue实例或组件上的内置属性和方法&#xff0c;这些被称为“实例属性”或“实例方法”。以下是一些常见的以$开头的Vue实例属性和方法 1.1、实例属性 序号实例属性解释1$dataVue实例的数据对象&#xff0c;用于存储组件…

SpringMVC与SpringBoot的区别

SpringMVC 和 Spring Boot 都是 Spring 框架的一部分&#xff0c;但它们的功能和目标有明显的不同。 形式上&#xff1a;SpringBoot是一个自动化配置的工具&#xff1b;SpringMVC是一个web框架。 在搭建项目时&#xff1a;SpringMVC需要手动配置xml文件&#xff0c;同时需要配…