Leetcode算法训练日记 | day34

news2024/10/6 18:35:58

专题九  贪心算法

一、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 大于 0
                nums[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.coloradmin.cn/o/1619115.html

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

相关文章

python爬虫 - 爬取html中的script数据(36kr.com新闻信息)

文章目录 1. 分析页面内容数据格式2. 使用re.findall方法&#xff0c;爬取新闻3. 使用re.search 方法&#xff0c;爬取新闻 1. 分析页面内容数据格式 打开 https://36kr.com/ 按F12&#xff08;或 在网页上右键 --> 检查&#xff08;Inspect&#xff09;&#xff09; 找…

HarmonyOS开发案例:【相机开发】

基本概念 相机是OpenHarmony多媒体进程提供的服务之一&#xff0c;提供了相机的录像、预览、拍照功能&#xff0c;支持多用户并发取流。 在进行应用的开发前&#xff0c;开发者应了解以下基本概念&#xff1a; 视频帧 视频流指的是将一系列图片数据按照固定时间间隔排列形成的…

开发日志(20240422):一次以为是跨域但并不是跨域的问题排查记录

1. 日志 在前后端联调的时候&#xff0c;遇到了报错&#xff0c;如下图所示&#xff08;现在再看感觉非常简单了&#xff09;&#xff0c;发现前一个请求通过了&#xff0c;但是第二个请求报错&#xff0c;然后看到 strict-origin-when-cross-origin 条件反射的认为是跨域配置…

iOS - 多线程-GCD-队列组

文章目录 iOS - 多线程-GCD-队列组1. 队列组1.1 基本使用步骤 iOS - 多线程-GCD-队列组 开发过程中&#xff0c;有时候想实现这样的效果 多个任务并发执行所有任务执行完成后&#xff0c;进行下一步处理&#xff08;比如回到主线程刷新UI&#xff09; 1. 队列组 可以使用GC…

探索开源的容器引擎--------------Docker容器操作

目录 一、Docker 容器操作 1.1容器创建 1.2查看容器的运行状态 1.3启动容器 1.4创建并启动容器 1.4.1当利用 docker run 来创建容器时&#xff0c; Docker 在后台的标准运行过程是&#xff1a; 1.4.2在后台持续运行 docker run 创建的容器 1.4.3创建容器并持续运行容器…

Swift-27-类的初始化与销毁

Swift的初始化是一个有大量规则的固定过程。初始化是设置类型实例的操作&#xff0c;包括给每个存储属性初始值&#xff0c;以及一些其他准备工作。完成这个过程后&#xff0c;实例就可以使用了。 简单来讲就是类的构造函数&#xff0c;基本语法如下&#xff1a; 注意&#xff…

3节点ubuntu24.04服务器docker-compose方式部署高可用elk+kafka日志系统并接入nginx日志

一&#xff1a;系统版本: 二&#xff1a;部署环境&#xff1a; 节点名称 IP 部署组件及版本 配置文件路径 机器CPU 机器内存 机器存储 Log-001 10.10.100.1 zookeeper:3.4.13 kafka:2.8.1 elasticsearch:7.7.0 logstash:7.7.0 kibana:7.7.0 zookeeper:/data/zookeep…

贪心算法在单位时间任务调度问题中的应用

贪心算法在单位时间任务调度问题中的应用 一、引言二、问题描述与算法设计三、算法证明四、算法实现与效率分析五、C语言实现示例六、结论 一、引言 单位时间任务调度问题是一类经典的优化问题&#xff0c;旨在分配任务到不同的时间槽中&#xff0c;使得某种性能指标达到最优。…

【JAVA】UDP与TCP套接字编程

目录 一、UDP数据报套接字编程 1、DatagramSocket API 2、DatagramPacket API 3、InetSocketAddress API 4、示例一 5、示例二 二、TCP流套接字编程 1、ServerSocket API 2、Socket API 3、TCP中的长短连接 4、示例一 5、示例二 一、UDP数据报套接字编程 1、Datag…

《ElementPlus 与 ElementUI 差异集合》el-select 显示下拉列表在 Cesium 场景中无法监听关闭

前言 仅在 Element UI 时有此问题&#xff0c;Element Plus 由于内部结构差异较大&#xff0c;不存在此问题。详见《el-select 差异点&#xff0c;如&#xff1a;高、宽、body插入等》&#xff1b; 问题 点击空白处&#xff0c;下拉列表可监听并关闭&#xff1b;但在 Cesium…

图解《图搜索算法》及代码实现

关注我&#xff0c;持续分享逻辑思维&管理思维&#xff1b; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导&#xff1b; 有意找工作的同学&#xff0c;请参考博主的原创&#xff1a;《面试官心得--面试前应该如何准备》&#xff0c;《面试官心得--面试时如何进行自…

Jmeter之Beanshell详解

一、 Beanshell概念 Beanshell: BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;BeanShell是一种松散类型的脚本语言(这点和JS类似);BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性…

LayuiMini使用时候初始化模板修改(下载源码)

忘记加了 下载 地址 &#xff1a; layui-mini: layuimini&#xff0c;后台admin前端模板&#xff0c;基于 layui 编写的最简洁、易用的后台框架模板。只需提供一个接口就直接初始化整个框架&#xff0c;无需复杂操作。 LayuiMini使用时候初始化模板官网给的是&#xff1a; layu…

用Excel做一个功能完备的仓库管理系统

1 基本设计思路 用到的Excel技术&#xff1a;sumif, vlookup, 表格(table)。基本思路&#xff1a;在有基础的商品、仓库等信息的情况下&#xff0c;对商品的每一个操作都有对应的单据&#xff0c;然后再汇总统计。标识&#xff1a;为了在不同的维度统计数量&#xff0c;各单据…

国产FTP文件传输服务器需要具备哪些关键特性?

国产FTP文件传输服务器是指根据中国国内信息技术创新&#xff08;信创&#xff09;的要求和标准&#xff0c;自主研发的文件传输服务器软件。这类软件旨在替代传统的FTP服务器&#xff0c;以更好地适应国产化和信息安全的需要。国产FTP文件传输服务器通常需要具备以下要求&…

图书租赁系统-扣费服务

resources中添加moment.js文件。 然后引入moment.js文件&#xff1a; <script src"/js/moment.js"></script>借阅结束时间选完后changeDate事件&#xff1a; $("input[nameendTime]").datetimepicker({format: "yyyy-mm-dd hh:ii",…

Linux:进程与计划任务

文章目录 Linux&#xff1a;进程与计划任务一、进程1、进程是什么2、进程状态 二、列出进程命令1、查看静态的进程统计信息——“ps”Play1&#xff1a;“ps aux”Play2:ps -elf 2、查看静态的进程统计信息——“top”段首解析进程信息区解释 三、运行与终止进程3.1、运行进程3…

为什么要写技术方案?

技术方案是为研究解决各类技术问题&#xff0c;有针对性&#xff0c;系统性的提出的方法、应对措施及相关对策。技术方案设计是一个技术开发者必备的能力&#xff0c;特别是对于高级、资深、架构师等角色。技术方案设计不仅能够帮助我们明确需求&#xff0c;规划架构&#xff0…

2024新算法爱情进化算法(LEA)和经典灰狼优化器(GWO)进行无人机三维路径规划设计实验

简介&#xff1a; 2024新算法爱情进化算法&#xff08;LEA&#xff09;和经典灰狼优化器&#xff08;GWO&#xff09;进行无人机三维路径规划设计实验。 无人机三维路径规划的重要意义在于确保飞行安全、优化飞行路线以节省时间和能源消耗&#xff0c;并使无人机能够适应复杂环…

windows系统下python开发工具安装

一. 简介 前一篇文章学习了安装 python解释器&#xff0c;文章如下&#xff1a; windows系统下python解释器安装-CSDN博客 本文来学习如何下载安装 python开发工具 PyCharm。 二. python开发工具 PyCharm下载安装 1. PyCharm官网 PyCharm开发工具 PyCharm为 python代码…