Leetcode算法训练日记 | day35

专题九  贪心算法

一、柠檬水找零

1.题目

Leetcode:第 860 题

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

示例 1:

输入:bills = [5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。

示例 2:

输入:bills = [5,5,10,10,20]
输出:false
解释:
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零,所以答案是 false。

2.解题思路

使用贪心算法解决柠檬水找零问题。

lemonadeChange 函数中,使用三个变量 fivetentwenty 来跟踪不同面额纸币的数量。我们遍历 bills 数组,根据账单面额更新纸币数量,并确保在任何时候都有足够的纸币来找零。如果在任何时候无法找零,函数将返回 false。如果所有账单都能被成功处理,函数最终返回 true。这个方法利用了贪心算法的思想,总是优先使用面额较大的纸币来找零,以便保留更多的小面额纸币,从而提高找零的灵活性。

3.实现代码

#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    // lemonadeChange 函数用于检查是否有足够的零钱来找零给所有顾客
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0, twenty = 0;// 初始化三种纸币的数量:5美元、10美元和20美元
       
        // 遍历 bills 中的每个账单
        for (int bill : bills) {
            // 情况一:顾客支付了5美元
            if (bill == 5) {
                five++; // 5美元纸币的数量加1
            }
            // 情况二:顾客支付了10美元
            if (bill == 10) {
                // 如果没有5美元纸币,无法找零,返回false
                if (five <= 0) return false;
                ten++; // 10美元纸币的数量加1
                five--; // 用一张5美元纸币找零
            }
            // 情况三:顾客支付了20美元
            if (bill == 20) {
                // 优先使用10美元和5美元的组合来找零,因为这样可以保留更多的5美元纸币
                if (five > 0 && ten > 0) {
                    five--; // 使用一张5美元纸币
                    ten--;  // 使用一张10美元纸币
                    // twenty++ 这行代码可以删除,因为后续不会再使用20美元纸币
                }
                else if (five >= 3) {
                    // 如果没有10美元纸币,需要三张5美元纸币来找零
                    five -= 3; // 使用三张5美元纸币
                    // twenty++ 这行代码也可以删除,理由同上
                }
                else {
                    // 如果既没有10美元纸币也没有足够的5美元纸币,无法找零,返回false
                    return false;
                }
            }
        }
        // 如果遍历完所有账单都能成功找零,返回true
        return true;
    }
};

//测试
int main()
{
    Solution p;
    vector<int> bills = { 5, 5, 5, 10, 20 };
    bool result = p.lemonadeChange(bills);
    cout << "能否给每位顾客正确找零:" << result << endl;
    cout << endl;
    return 0;
}

 

 

二、根据身高重建队列

1.题目

Leetcode:第 406 题

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

示例 1:

输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
解释:
编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。

示例 2:

输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]
2.解题思路

使用贪心算法解决根据身高重建队列问题。

reconstructQueue 函数中,我们首先使用 sort 函数和一个自定义的比较函数 cmp 对输入的 people 进行排序。cmp 函数确保了身高更高的人排在前面,如果身高相同,则原始位置较小的人排在前面。排序后,我们遍历 people,并使用 vectorinsert 方法在新队列 que 的适当位置插入每个人。由于 people 已经根据身高和原始位置排序,插入操作会保持这些人的相对顺序,从而重构出原始的队列。最终,函数返回重构后的队列 que

3.实现代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
    // cmp 函数用于比较两个 vector<int> 对象的大小
    // 这个函数被用作 sort 函数的比较函数
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        // 如果第一个元素相同,则比较第二个元素
        // 如果第二个元素小的排在前面,则返回 true
        if (a[0] == b[0]) return a[1] < b[1];
        // 否则,比较第一个元素,第一个元素大的排在前面
        return a[0] > b[0];
    }

    // reconstructQueue 函数用于重构一个队列
    // people 是一个 vector<vector<int>> 对象,其中每个内部 vector 包含两个整数
    // 第一个整数表示人的身高,第二个整数表示在队列中的原始位置
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // 使用自定义的比较函数对 people 进行排序
        // 排序规则是:首先按照身高降序,如果身高相同,则按照原始位置升序
        sort(people.begin(), people.end(), cmp);

        // 初始化队列,将用于存放最终的队列顺序
        vector<vector<int>> que;

        // 遍历排序后的 people
        for (int i = 0; i < people.size(); i++) {
            // 获取当前人的原始位置
            int position = people[i][1];
            // 在 que 的 position 位置插入当前人
            // 由于 vector 的插入操作会移动元素,所以这将重建原始的队列顺序
            que.insert(que.begin() + position, people[i]);
        }

        // 返回重构后的队列
        return que;
    }
};

//测试
int main()
{
    Solution p;
    vector<vector<int>> people = {{7, 0}, {4, 4}, {7, 1}, {5, 0}, {6, 1}, {5, 2}};
    vector<vector<int>> result = p.reconstructQueue(people);
    cout << "重构后的队列:"<<endl;
    for (auto& ans : result) {
        cout << "[";
        for (auto& i : ans) {
            cout << i << ",";
        }
        cout << "]" << " ,";
    }
    cout << endl;
    cout << endl;
    return 0;
}

 

 

三、用最少数量的箭引爆气球

1.题目

Leetcode:第 452 题

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstartxend, 且满足  xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 

 

示例 1:

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。

示例 2:

输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。

示例 3:

输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:
- 在x = 2处发射箭,击破气球[1,2]和[2,3]。
- 在x = 4处射出箭,击破气球[3,4]和[4,5]。
2.解题思路

使用贪心算法解决用最少数量的箭引爆气球问题。

findMinArrowShots 函数中,我们首先检查 points 是否为空,如果为空,直接返回 0。然后,我们使用 sort 函数和一个自定义的比较函数 cmppoints 进行排序,确保所有气球按照起始时间的升序排列。接下来,我们初始化 result 为 1,因为至少需要一支箭来射爆第一个气球。之后,我们遍历 points,检查每个气球是否与前一个气球重叠。如果重叠,我们更新它们的结束时间;如果不重叠,我们增加 result 的值,因为这表示需要额外一支箭。最终,函数返回 result,即射爆所有气球所需的最小箭数。

3.实现代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

class Solution {
private:
    // cmp 函数用于比较两个 vector<int> 对象,即比较两个气球的起始时间
    // 这个函数被用作 sort 函数的比较函数
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] < b[0]; // 返回 a 的起始时间是否小于 b 的起始时间
    }

public:
    // findMinArrowShots 函数用于找出最少需要多少支箭来射爆所有气球
    int findMinArrowShots(vector<vector<int>>& points) {
        // 如果 points 为空,不需要箭
        if (points.size() == 0) return 0;

        // 对 points 进行排序,按照气球的起始时间进行升序排序
        sort(points.begin(), points.end(), cmp);

        // 初始化结果 result 为 1,因为即使只有一个气球,也需要至少一支箭
        int result = 1;

        // 遍历 points,从第二个气球开始(索引为 1)
        for (int i = 1; i < points.size(); i++) {
            // 如果当前气球的起始时间大于前一个气球的结束时间,说明它们不重叠
            if (points[i][0] > points[i - 1][1]) {
                // 气球 i 和气球 i-1 不挨着,需要额外一支箭
                result++;
            }
            else {
                // 如果当前气球与前一个气球重叠(相邻),则更新重叠气球的最小结束时间
                // 取前一个气球的结束时间和当前气球的结束时间的较小值作为新的结束时间
                points[i][1] = min(points[i - 1][1], points[i][1]);
            }
        }
        return result;// 返回所需的最小箭数
    }
};

//测试
int main()
{
    Solution p;
    vector<vector<int>> points = { {10,16} ,{2,8},{1,6},{7,12} };
    int result = p.findMinArrowShots(points);
    cout << "所需的最小箭数:" << result << endl;
    cout << endl;
    return 0;
}

 

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为什么建议游戏工作室使用海外住宅IP防封?

当谈到游戏工作室时&#xff0c;它们通常以多开游戏账号来获取收益为主要目标。这种商业模式在游戏产业中已经成为一个独特而且颇具潜力的领域。然而&#xff0c;随之而来的是防封问题&#xff0c;特别是当游戏工作室试图通过多开账号来赚取更多收益时。因此&#xff0c;我们有…

【第6节】Lagent AgentLego 智能体应用搭建

目录 1 基础课程2 安装环境2.1 教程要求2.2 安装 Lagent 和 AgentLego 3 实践操作3.1 Lagent&#xff1a;轻量级智能体框架3.1.1 Lagent Web Demo 使用3.1.2 用 Lagent 自定义工具 3.2 AgentLego&#xff1a;组装智能体“乐高”3.2.1 AgentLego 直接使用部分3.2.2 AgentLego We…

【Harmony3.1/4.0】笔记二

概述 列表是一种复杂的容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。它适合用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本。在列表中显示数据集合是许多应用程序中的常见要求&#xff08;如通讯录、…

linux——yum工具详解

yum是linux中自动解决软件包依赖关系的管理器 同时&#xff0c;yum也是一个rpm软件 这里使用yum install nginx安装nginx

Windows SMBGhost CVE-2020-0796 Elevate Privileges

SMBGhost CVE-2020-0796 Microsoft Windows 10 (1903/1909) - ‘SMBGhost’ SMB3.1.1 ‘SMB2_COMPRESSION_CAPABILITIES’ Local Privilege Escalation https://www.exploit-db.com/exploits/48267 Github https://github.com/danigargu/CVE-2020-0796 修改载荷[可选] 生成 c# …

用c++实现起泡排序、哈密顿回路问题、TSP问题

5.3.2 起泡排序 【问题】 起泡排序(bubble sort)的基本思想是&#xff1a;两两比较相邻记录&#xff0c;如果反序则交换&#xff0c;直至没有反序的记录&#xff0c;如图5.8所示。【想法】下表给出了一个起泡排序的例子&#xff08;方括号括起来的为无序区&#xff09;&#x…

深入理解JavaScript:对象什么时候创建

&#x1f31f; 我们在chrome浏览器中debug程序。为了好debug我们会写一些在日常开发中基本不会采用的代码书写方式。 JavaScript中创建对象有3中方式&#xff1a; 1、对象字面量&#xff1b; 2、new&#xff1b; 3、Object.create(对象)&#xff1b; 1、使用new创建对象 fun…

MicroSIP电话呼叫软件使用及配置方法

MicroSIP是一款开源的SIP协议电话软件&#xff0c;它可以帮助你在计算机上进行语音和视频通话。下面是关于如何使用和配置MicroSIP的一些基本步骤&#xff1a; 安装MicroSIP 从MicroSIP官方网站下载适合你操作系统的安装包23。 解压下载的文件&#xff0c;并运行安装程序。 …

GRPC学习笔记

GRPC学习笔记 1 GRPC简介 1.1 定义 gRPC&#xff08;Google Remote Procedure Call&#xff0c;Google远程过程调用&#xff09;协议是谷歌发布的基于HTTP2协议承载的高性能、通用的RPC开源软件框架&#xff0c;提供了支持多种编程语言的、对网络设备进行配置和管理的方法。…

更新至2022年上市公司数字化转型数据合集(四份数据合集)

更新至2022年上市公司数字化转型数据合集&#xff08;四份数据合集&#xff09; 一、2000-2022年上市公司数字化转型数据&#xff08;年报词频、文本统计&#xff09; 二、2007-2022年上市公司数字化转型数据&#xff08;年报和管理层讨论&#xff09;&#xff08;含原始数据…

Java中的运算符

运算符是用于数学函数、一些特殊的赋值语句和逻辑比较方面的特殊符号。 赋值运算符&#xff08;“”&#xff09; 赋值运算符是一个二元运算符&#xff08;即对两个操作数进行处理&#xff09;&#xff0c;功能是将右侧的操作数赋值给左侧的操作数。 int a 100; 该表达式就…

prometheus配置监控Java应用服务

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

从底层分析并详解SpringAOP底层实现

首先分析AOP的实现 首先切面&#xff08;Advisor&#xff09;由通知(Advice)和切点(Pointcut)组成 包括前置通知后置通知等等最终都会被转化为实现 MethodInterceptor 接口的环绕通知 先看一段代码了解一下是aop是怎么运作的 首先定义了两个类实现了MethodInterceptor接口&…

XiaodiSec day017 Learn Note 小迪安全学习笔记

XiaodiSec day017 Learn Note 小迪安全学习笔记 记录得比较凌乱&#xff0c;不尽详细 day 17 主要内容&#xff1a; php 框架 thinkPHPyiilaravel 使用 fofa 搜索 thinkphp 市面上 thinkphp5 版本较多 url 结构 域名/.php(文件名)/index(目录)/index(函数名)模块名-控…

oracle 12c+ max_string_size参数

一个客户的数据库版本是19.3,在做数据库复制的时候,目标端报错了,查看了一下问题发现表的字段长度有不对,在12c以前我们都知道varchar的长度最大是4000,但是客户这里居然有32767: 把客户的建表语句弄出来,放到我的一个19c的测试环境进行测试: 发现报错了: 这里报错很明显了,是M…

不可思议!我的AI有道英语字典助手竟然与百度千帆AI应用创意挑战赛K12教育主题赛榜首作品差之毫厘

目录 一、前言二、效果对比三、优化《AI英语词典》提示词四、其他获奖作品链接 一、前言 今天看百度千帆AI原生应用创意挑战赛——K12教育主题赛&#xff0c;发现第一名的《我爱记单词》和我早两天发布的一篇《AI英语词典》的想法不谋而合。当时我们应该都是互相不知道对方的&a…

Day1--什么是网络安全?网络安全常用术语

目录 1. 什么是网络安全&#xff1f; 信息系统&#xff08;Information System&#xff09; 信息系统安全三要素&#xff08;CIA&#xff09; 网络空间安全管理流程 网络安全管理 2. 网络安全的常用术语 3. 网络安全形势 4. 中国网络安全产业现状 1. 什么是网络安全&am…

使用IOPaint实现图片擦除路人

IOPaint 是一个免费的开源的 inpainting/outpainting 工具&#xff0c;由最先进的 AI 模型提供支持。 IOPaint 中使用各种模型来修改图像&#xff1a; 擦除&#xff1a;删除任何不需要的物体、缺陷、水印、人物。修复&#xff1a;对图像的特定部分进行修改、添加新对象或替换…

第二期书生浦语大模型训练营第四次笔记

大模型微调技术 大模型微调是一种通过在预训练模型的基础上&#xff0c;有针对性地微调部分参数以适应特定任务需求的方法。 微调预训练模型的方法 微调所有层&#xff1a;将预训练模型的所有层都参与微调&#xff0c;以适应新的任务。 微调顶层&#xff1a;只微调预训练模型…

ACL的知识点和实验

1.ACL的组成 ACL由若干条permit或deny语句组成。每条语句就是该ACL的一条规则&#xff0c;每条语句中的permit或deny就是与这条规则相对应的处理动作。 2.规则编号 &#xff08;1&#xff09;一个ACL中的每一条规则都有一个相应的编号。 &#xff08;2&#xff09;步长是系…
最新文章