Leetcode算法训练日记 | day34

专题九  贪心算法

一、K次取反后最大化的数组和

1.题目

Leetcode:第 1005 题

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

  • 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

示例 1:

输入:nums = [4,2,3], k = 1
输出:5
解释:选择下标 1 ,nums 变为 [4,-2,3] 。

示例 2:

输入:nums = [3,-1,0,2], k = 3
输出:6
解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。

示例 3:

输入:nums = [2,-3,-1,5,-4], k = 2
输出:13
解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。

2.解题思路

使用贪心算法解决K次取反后最大化的数组和问题。

largestSumAfterKNegations 函数中,我们首先使用 sort 函数和一个自定义的比较函数 cmp 对数组 nums 进行排序。这个比较函数 cmp 使用 abs 函数比较两个数的绝对值,确保绝对值较大的负数排在前面。接着,我们遍历数组,将前 k 个负数取反。如果 k 是奇数,且遍历结束后仍有剩余的 k,则将最后一个元素取反。最后,我们初始化一个变量 result 来存储最终的和,并遍历排序并取反后的数组 nums,将所有元素相加得到最终结果。这个方法利用了贪心算法的思想,即在每一步选择中都尝试达到最优化的结果,从而希望导致结果是全局最优的。

3.实现代码

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;class Solution {// 定义一个静态比较函数,用于自定义排序规则static bool cmp(int a, int b) {return abs(a) > abs(b); // 返回绝对值比较的结果,确保绝对值大的负数排在前面}
public:// largestSumAfterKNegations 函数用于计算最大约和int largestSumAfterKNegations(vector<int>& nums, int k) {sort(nums.begin(), nums.end(), cmp); // 使用自定义的比较函数对数组进行排序// 遍历数组for (int i = 0; i < nums.size(); i++) {if (nums[i] < 0 && k > 0) {// 如果当前元素是负数且 k 大于 0nums[i] = nums[i] * (-1);// 将当前元素取反,并减少 k 的值k--;}}// 如果 k 是奇数,最后一个元素取反if (k % 2 == 1) {nums[nums.size() - 1] *= -1;}int result = 0;// 初始化结果变量for (int a : nums) {result += a;// 遍历排序后的数组,计算所有元素的和}return result; // 返回计算得到的结果}
};//测试
int main()
{Solution p;vector<int> nums = { 4,2,3 };int k = 1;int result = p.largestSumAfterKNegations(nums,k);cout << "nums数组可能的最大和:" << result << endl;cout << endl;return 0;
}

二、加油站

1.题目

Leetcode:第 134 题

在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。

你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。

给定两个整数数组 gas 和 cost ,如果你可以按顺序绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。

示例 1:

输入: gas = [1,2,3,4,5], cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。

示例 2:

输入: gas = [2,3,4], cost = [3,4,3]
输出: -1
解释:
你不能从 0 号或 1 号加油站出发,因为没有足够的汽油可以让你行驶到下一个加油站。
我们从 2 号加油站出发,可以获得 4 升汽油。 此时油箱有 = 0 + 4 = 4 升汽油
开往 0 号加油站,此时油箱有 4 - 3 + 2 = 3 升汽油
开往 1 号加油站,此时油箱有 3 - 3 + 3 = 3 升汽油
你无法返回 2 号加油站,因为返程需要消耗 4 升汽油,但是你的油箱只有 3 升汽油。
因此,无论怎样,你都不可能绕环路行驶一周。
2.解题思路

(1)一般解法

(2)使用贪心算法解决加油站问题。

canCompleteCircuit 函数中,我们使用两个变量 curSumtotalSum 分别来记录当前窗口的剩余油量和整个数组的总剩余油量。同时,我们使用变量 start 来记录可能的环绕起始位置。循环遍历每个油量和消耗的位置,我们将当前位置的油量减去消耗,并累加到 curSumtotalSum 中。如果 curSum 小于 0,这意味着从当前起始位置开始的窗口内无法环绕一圈,因此我们将 start 移动到下一个位置,并将 curSum 重置为 0,以便开始计算新的窗口。在循环结束后,我们检查 totalSum,如果它小于 0,则表示在整个数组范围内无法环绕一圈,因此返回 -1。否则,我们返回 start 作为可能的环绕起始位置。这种方法利用了贪心算法的思想,通过维护一个滑动窗口的剩余油量来找到可能的环绕起始位置。

3.实现代码
#include <iostream>
#include <vector>
using namespace std;// 一、一般解法
class Solution1 {
public:// canCompleteCircuit 函数用于判断是否能够环绕一圈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();// 初始化下一个检查的位置为当前位置后的第一个位置// 模拟从当前位置 i 开始环绕行驶while (rest > 0 && index != i) {// 更新剩余油量,如果下一个位置的油量加上剩余油量大于等于消耗,则继续前进rest += gas[index] - cost[index];// 移动到下一个位置index = (index + 1) % cost.size();}// 如果从位置 i 开始能够环绕一圈回到起始位置,并且剩余油量非负,则返回起始位置if (rest >= 0 && index == i) return i;}return -1;// 如果没有找到可以环绕一圈的起始位置,返回 -1}
};// 二、贪心算法
class Solution2 {
public:// canCompleteCircuit 函数用于判断是否能够环绕一圈int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int curSum = 0; // 初始化当前窗口的剩余油量int totalSum = 0; // 初始化整个数组的总剩余油量int start = 0; // 初始化可能的起始位置// 遍历油量和消耗的对应位置for (int i = 0; i < gas.size(); i++) {curSum += gas[i] - cost[i];// 将当前位置的油量和消耗相减,并加到当前窗口的剩余油量上totalSum += gas[i] - cost[i];// 将当前位置的油量和消耗相减,并加到总剩余油量上// 如果当前窗口的剩余油量小于 0,说明当前窗口内无法环绕一圈if (curSum < 0) {start = i + 1;// 重置起始位置为当前位置之后,即窗口滑动到下一个位置curSum = 0;// 重置当前窗口的剩余油量为 0}}// 如果整个数组的总剩余油量小于 0,说明整个数组内无法环绕一圈if (totalSum < 0) return -1;return start;// 返回可能的环绕起始位置}
};//测试
int main()
{Solution2 p;vector<int> gas = { 1,2,3,4,5 };vector<int> cost = { 3,4,5,1,2 };int result = p.canCompleteCircuit(gas, cost);cout << "可能的环绕起始位置:" << result << endl;cout << endl;return 0;
}

  

三、分发糖果

1.题目

Leetcode:第 135 题

n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。

你需要按照以下要求,给这些孩子分发糖果:

  • 每个孩子至少分配到 1 个糖果。
  • 相邻两个孩子评分更高的孩子会获得更多的糖果。

请你给每个孩子分发糖果,计算并返回需要准备的 最少糖果数目 。

示例 1:

输入:ratings = [1,0,2]
输出:5
解释:你可以分别给第一个、第二个、第三个孩子分发 2、1、2 颗糖果。

示例 2:

输入:ratings = [1,2,2]
输出:4
解释:你可以分别给第一个、第二个、第三个孩子分发 1、2、1 颗糖果。第三个孩子只得到 1 颗糖果,这满足题面中的两个条件。
2.解题思路

使用贪心算法解决分发糖果问题。

candy 函数中,我们首先创建了一个与 ratings 数组等长的 candyVec 数组,所有元素初始为 1,表示每个孩子至少得到 1 个糖果。

然后,我们进行两次遍历:

  1. 第一次从前向后遍历 ratings 数组,如果一个孩子的评分高于他左边的孩子,那么他的糖果数量应该比左边的孩子多一个。

  2. 第二次从后向前遍历 ratings 数组,如果一个孩子的评分高于他右边的孩子,那么他的糖果数量应该取右边孩子糖果数量加一和当前数量中的较大值。最后,我们遍历 candyVec 数组,将所有孩子的糖果数量累加起来,得到总共需要的糖果数量,并返回这个结果。这种方法利用了贪心算法的思想,通过维护一个糖果数组来动态地计算每个孩子应该得到的糖果数量。

3.实现代码
#include <iostream>
#include <vector>
using namespace std;class Solution {
public:// candy 函数用于计算分配糖果的最少数量int candy(vector<int>& ratings) {// 初始化一个与 ratings 大小相同的数组 candyVec,所有元素初始为 1// 这个数组将用于存储每个孩子应该得到的糖果数量vector<int> candyVec(ratings.size(), 1);// 从 ratings 数组的第二个元素开始向前遍历for (int i = 1; i < ratings.size(); i++) {if (ratings[i] > ratings[i - 1]) { // 如果当前孩子的评分高于他左边的孩子candyVec[i] = candyVec[i - 1] + 1;// 那么当前孩子的糖果数量应该比左边的孩子多一个}}// 从 ratings 数组的倒数第二个元素开始向前遍历for (int i = ratings.size() - 2; i >= 0; i--) {if (ratings[i] > ratings[i + 1]) {// 如果当前孩子的评分高于他右边的孩子candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);// 那么当前孩子的糖果数量应该取右边孩子糖果数量加一和当前数量中的较大值}}int result = 0;// 初始化结果变量 result,用于计算总共需要的糖果数量// 遍历 candyVec 数组,将所有孩子的糖果数量累加到 result 中for (int i = 0; i < candyVec.size(); i++) {result += candyVec[i];}return result;// 返回总共需要的糖果数量}
};//测试
int main()
{Solution p;vector<int> ratings = { 1, 0, 2 };int result = p.candy(ratings);cout << "总共需要的糖果数量:" << result << endl;cout << endl;return 0;
}

 ps:以上皆是本人在探索算法旅途中的浅薄见解,诚挚地希望得到各位的宝贵意见与悉心指导,若有不足或谬误之处,还请多多指教。

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

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

相关文章

【大语言模型LLM】- Meta开源推出的新一代大语言模型 Llama 3

&#x1f525;博客主页&#xff1a;西瓜WiFi &#x1f3a5;系列专栏&#xff1a;《大语言模型》 很多非常有趣的模型&#xff0c;值得收藏&#xff0c;满足大家的收集癖&#xff01; 如果觉得有用&#xff0c;请三连&#x1f44d;⭐❤️&#xff0c;谢谢&#xff01; 长期不…

git常见命令(成长版)

ps&#xff1a;所谓成长版就是后续可能还会添加命令&#xff1a; 1.删除本地分支&#xff1a; git branch -d 分支名 2.拉取代码后默认master分支&#xff0c;切换到线上其他分支&#xff1a; &#xff08;1&#xff09;查看线上所有分支&#xff1a; git branch -a &#…

【STM32+HAL+Proteus】系列学习教程4---GPIO输入模式(独立按键)

实现目标 1、掌握GPIO 输入模式控制 2、学会STM32CubeMX配置GPIO的输入模式 3、具体目标&#xff1a;1、按键K1按下&#xff0c;LED1点亮&#xff1b;2、按键K2按下&#xff0c;LED1熄灭&#xff1b;2、按键K3按下&#xff0c;LED2状态取反&#xff1b; 一、STM32 GPIO 输入…

基于小程序实现的查寝打卡系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

[Algorithm][前缀和][模板 一维前缀和][模板 二维前缀和][寻找数组中心下标][除自身以外数组的乘积] + 前缀和原理 + 前缀和模板

目录 0.原理讲解1.[模板]一维前缀和1.题目链接2.模板代码实现 2.[模板]二维前缀和1.题目链接2.算法原理讲解3.模板代码实现 3.寻找数组的中心下标1.题目链接2.算法原理详解3.代码实现 4.除自身以外数组的乘积1.题目链接2.算法原理详解3.代码实现 0.原理讲解 前缀和&#xff1a;…

Docker学习(二十五)构建 Arthas 基础镜像

目录 一、简介二、构建基础镜像2.1 下载 Arthas2.2 编写 Dockerfile2.3 构建镜像2.4 创建容器2.5 测试 一、简介 Arthas 是一款由 阿里巴巴 开发的 线上监控诊断工具。通过全局视角实时查看应用负载、内存、GC、线程等信息&#xff0c;能在不修改代码的情况下&#xff0c;对业…

Pytorch常用的函数(八)常见优化器SGD,Adagrad,RMSprop,Adam,AdamW总结

Pytorch常用的函数(八)常见优化器SGD,Adagrad,RMSprop,Adam,AdamW总结 在深度学习中&#xff0c;优化器的目标是通过调整模型的参数&#xff0c;最小化&#xff08;或最大化&#xff09;一个损失函数。 优化器使用梯度下降等迭代方法来更新模型的参数&#xff0c;以使损失函数…

【QT进阶】Qt http编程之实现websocket server服务器端

往期回顾 【QT进阶】Qt http编程之json解析的简单介绍-CSDN博客 【QT进阶】Qt http编程之nlohmann json库使用的简单介绍-CSDN博客 【QT进阶】Qt http编程之websocket的简单介绍-CSDN博客 【QT进阶】Qt http编程之实现websocket server服务器端 一、最终效果 通过ip地址和端口…

人工智能时代的关键技术:深入探索向量数据库及其在AI中的应用

文章目录 1. 理解向量数据库&#xff1a;二维模型示例2. 向量数据库中的数据存储与检索3. 向量数据库如何工作&#xff1f;4. 向量数据库如何知道哪些向量相似&#xff1f; 在人工智能技术日益成熟的当下&#xff0c;向量数据库作为处理和检索高维数据的关键工具&#xff0c;对…

Dropout Feature Ranking for Deep Learning Models

摘要 深度神经网络( deep neural networks&#xff0c;DNNs )在多个领域取得了最新的研究成果。不幸的是&#xff0c;DNNs因其不可解释性而臭名昭著&#xff0c;从而限制了其在生物和医疗保健等假说驱动领域的适用性。此外&#xff0c;在资源受限的环境下&#xff0c;设计依赖…

Linux下的UDEV机制/守护进程

一. Udev机制概念引入 ( 需要在 etc/udev/rules.d/ 下创建设备的相关规则&#xff0c;不然有可能udev机制生成的设备文件不具备可读可写的权限&#xff0c;adb无法成功通过该设备文件访问设备 ) a. 创建文件夹 sudo vim Xiaomi-audroid.rules b. 添加规则 …

在vscode上面进行分支merge的记录

前言&#xff1a;在我们的项目中&#xff0c;有两个分支&#xff1a;master和liutielong。现在要将liutielong分支的改动merge到master分支中。 如果master分支已经更改了&#xff0c;所以要先pull&#xff08;这是在git bash里面的命令&#xff09;。 git pull origin master…

5分钟——快速搭建后端springboot项目

5分钟——快速搭建后端springboot项目 1. idea新建工程2. 构建pom.xml文件3. 构建application.yml配置文件4. 构建springboot启动类5. 补充增删改查代码6. 运行代码 1. idea新建工程 点击右上角新建一个代码工程 别的地方不太一样也不用太担心&#xff0c;先创建一个工程就好…

学习配置文件

1.yml的语法格式问题&#xff1a; 2.配置文件获取数据&#xff1a; Value方式&#xff1a; Environment&#xff1a; 获取自定义对象的方式&#xff1a; 设置get和set方法&#xff0c;还有toString方法。 3. 日志配置&#xff1a; logo的配置&#xff1a; 日志插件&#xff…

汽车纵染压制专用液压机比例阀放大器

汽车纵染压制专用液压机比例阀放大器是一种专门用于汽车纵梁拉伸工艺的设备&#xff0c;它也可以用于其他金属薄板的压制成型及校正工艺。该类型的液压机通常具备独立的动力机构和电气系统&#xff0c;采用PLC技术进行控制&#xff0c;以确保操作的准确性和稳定性。除了纵梁拉伸…

【iOS】分类,扩展与关联对象

文章目录 前言一、分类实现原理二、分类加载流程三、扩展四、类别与类扩展的区别五、关联对象动态添加取值移除关联对象应用 总结 前言 上一篇章我们探究了类与对象的底层&#xff0c;这一篇我们探究一下分类&#xff0c;扩展与关联对象 一、分类实现原理 首先我们知道扩展是…

CentOS-7安装grafana

一、通用设置&#xff08;分别在4台虚拟机设置&#xff09; 1、配置主机名 hostnamectl set-hostname --static 主机名2、修改hosts文件 vim /etc/hosts 输入&#xff1a; 192.168.15.129 master 192.168.15.133 node1 192.168.15.134 node2 192.168.15.136 node33、 保持服…

GaussianEditor:快速可控的3D编辑与高斯飞溅

GaussianEditor: Swift and Controllable 3D Editing with Gaussian Splatting GaussianEditor&#xff1a;快速可控的3D编辑与高斯飞溅 Yiwen Chen*​1,2   Zilong Chen*​3,5   Chi Zhang2   Feng Wang3   Xiaofeng Yang2 陈怡雯 *​1,2 陈子龙 *​3,5 张驰 2 王峰 3 杨晓…

MySQL学习笔记7——视图和存储过程

视图和存储过程 一、视图1、视图的作用2、如何操作视图和视图中的数据3、视图的优缺点 二、存储过程1、如何创建存储过程2、调用存储过程3、修改和删除存储过程 一、视图 1、视图的作用 视图是一种虚拟表&#xff0c;我们可以把一段查询语句作为视图存储在数据库中&#xff0…

liqo学习及安装,k8s,kubernetes多集群互联

先按照官方的教程在虚拟机安装学习 在开始以下教程之前&#xff0c;您应该确保您的系统上安装了以下软件&#xff1a; Docker&#xff0c;容器运行时。Kubectl&#xff0c;Kubernetes 的命令行工具。 curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.…