算法训练之贪心

news2025/4/16 1:59:17


♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥

♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥

♥♥♥我们一起努力成为更好的自己~♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥

✨✨✨✨✨✨ 个人主页✨✨✨✨✨✨

        在前面的博客中,我们已经学习了部分算法思路,可以解决一些问题了,这一篇博客我们来展开一个新的算法思想——贪心,准备好了吗~我们发车去探索奥秘啦~🚗🚗🚗🚗🚗🚗

目录

前置知识

什么是贪心算法?   

举例

找零钱问题

最小路径和问题

贪心算法的特点

柠檬水找零

将数组和减半的最小操作数

priority_queue

核心特性

常用操作


前置知识

        在真正开始贪心算法题目练习之前,我们首先要了解什么是贪心算法?贪心算法有什么特点?

什么是贪心算法?   

我们可以用一句话来概括:贪婪+鼠目寸光   

贪心策略: 解决问题的策略,由局部最优——>全局最优

具体步骤:

1.把解决问题的过程分为若干步;
2.解决每一步的时候,都选择当前看起来"最优的"解法;(鼠目寸光)
3."希望"得到全局最优解。(不一定就是最优解)

光光看这些步骤会有一点抽象,我们来结合具体例子来看~

举例

找零钱问题

        将要解决的问题分为几步,从最大的面值开始计算,找当前花的最少张数,显然答案是正确的,后续我们会进行证明~

最小路径和问题

        在前面动态规划我们提到过这个问题,这一次我们试一下使用贪心算法可不可以解决~

        从左上角开始,我们每一步都按当前位置的最优选择(局部最优解)进行,但是不难发现结果是错误的~所以我们是"希望"得到全局最优解,但是结果不一定近人意,我们就需要更改我们的贪心策略~

贪心算法的特点

结合前面的例子,我们可以发现贪心算法有下面的特点:

一、贪心策略的提出
        1.贪心策略的提出是没有标准以及模板的

        2.可能每一道题的贪心策略都是不同的

二、贪心策略的正确性
        "贪心策略"可能是一个错误的方法;正确的贪心策略,我们是需要"证明的"

        常用的证明的方法:数学中见过的所有证明方法

接下来,我们就来证明找零钱问题贪心策略的正确性:

        我们首先假设最优解得到的面值为20、10、5、1的张数分别为A、B、C、D,我们首先来看看它们的特点/性质:

相同的分析可以得到B、C、D满足B<=1,C<=1,D<=4

我们继续来看,假设贪心算法得到的面值为20、10、5、1的张数分别为a、b、c、d~

        既然最优解是最少的张数的话,那么我们显然a>=A的,那么我们来分析一下a>A的情况,a大于A说明还有20需要其他面值凑出来,但是B、C、D满足B<=1,C<=1,D<=4,所以最多就是19,不能凑出来20,那么就说明a==A,同理可以得到b==B,c==C,d==D,所以最优解的答案和贪心得到的答案是一样的,那么也就说明是正确的~

        因此,正确的贪心策略,我们是需要"证明的",证明结果正确才代表贪心策略正确,证明贪心策略不正确,只需要举一个反例,那么这个时候就需要我们对贪心策略进行调整了~


有了前面的这些小知识点,接下来,我们就来在题目中进行实际应用贪心算法~

柠檬水找零

柠檬水找零

        这个题目告诉了我们一杯柠檬水5美元,顾客可能给5美元/10美元/20美元,最开始我们手上没有任何的美元,这也就说明我们只能利用顾客给我们的钱进行找零~并且顾客是排队购买的,必须成功找了零钱才能继续收下一个顾客的钱~

        我们来进行分类讨论:

1、如果顾客给的钱是5美元——直接收下

2、如果顾客给的钱是10美元——需要找5美元

3、如果顾客给的钱是20美元——需要找15美元(这里的十五美元就有两种选择了)

                         ①10 + 5   ②5 + 5 + 5

        我们主要来分析一下第三种情况,我们优先选择第一种还是第二种呢?

        答案是第一种,我们不难发现5美元是有很大用处的,10美元可以找,20美元也可以找,结合我们的生活经验,我们应该尽可能的保留5美元~这里就体现了我们贪心思想,优先选择当前情况下的最优解,最终得到全局的最优解~

        有了前面的分析,这道题目的代码实现就比较简单了~

代码实现:

//柠檬水找零
class Solution
{
public:
    bool lemonadeChange(vector<int>& bills)
    {
        int n = bills.size();
        int five = 0, ten = 0;//统计可以找的钱
        for (auto x : bills)
        {
            if (x == 5)//是5元直接收下
            {
                five++;
            }
            else if (x == 10)//10元需要找5元
            {
                //判断是否有五元
                if (five)
                {
                    five--;
                    ten++;
                }
                else
                    return false;
            }
            else//20元需要找15元
            {
                //贪心思想
                //优先10+5
                if (five && ten)
                {
                    five--;
                    ten--;
                }
                //其次5+5+5
                else if (five >= 3)
                {
                    five -= 3;
                }
                //找不了就return false
                else
                    return false;
            }
        }
        return true;
    }
};

顺利通过~

将数组和减半的最小操作数

将数组和减半的最小操作数

题目要求是比较简单的,我们这里就直接来说一下我们的贪心策略:

贪心策略

        每一次找到数组中最大的数(我们可以使用大根堆)进行减半操作再把减半的数重新放入数组中,重复操作,找到整个数组和减少一半为止~

贪心策略知道了,代码实现也就更加简单了~

代码实现:


class Solution
{
public:
    int halveArray(vector<int>& nums)
    {
        //使用大根堆——每次找到最大值减少一半
        int n = nums.size();
        //减半之后可能是小数,使用double存储
        priority_queue<double> heap;
        //插入数据+统计数组和
        double sum = 0;
        for (auto e : nums)
        {
            heap.push(e);
            sum += e;
        }
        sum /= 2.0;//和先除2
        int count = 0;//计数
        while (sum > 0)//当减半和>0,进入循环
        {
            //找到堆顶元素减少一半重新插入
            double tmp = heap.top() / 2;
            heap.pop();
            sum -= tmp;
            heap.push(tmp);
            count++;
        }
        return count;
    }
};

顺利通过~接下来对我们的贪心策略进行简单的证明~

交换论证法证明:

        贪心解选择的数据:A 、B 、C 、D 、E.....x....

        最优解选择的数据:a 、 b 、c 、 d、 e......y...

贪心解每一次都是选择最大的数进行减半操作,那么说明贪心解选择的数据 >= 最优解选择的数据,数据相同的情况,我们就不需要处理了,如果说贪心解选择的数据(x)>最优解选择的数据(y)——分情况讨论

1、如果这个数据没有使用过,因为x > y,那么把最优解里面的数据y替换成x,肯定是可以达到数组和减少一半的操作的

2、如果这个数据使用过了,我们也可以把最优解里面的数据y替换成x,只不过更改一下顺序就可以了

        最终进行不断地替换完成之后,我们不难发现贪心解和最优解选择的数据个数是相等的,也就是我们想要的结果~

        证明结束~

此外,这一篇文章提到的priority_queue也在这里进行简单介绍

priority_queue

priority_queue(优先队列)是一个基于堆(Heap)结构的容器适配器,用于高效管理元素的优先级。以下是关键点介绍:

核心特性

  • 默认最大堆:默认使用大顶堆(最大元素在队首),可通过比较函数改为小顶堆。
  • 默认大顶堆:priority_queue<int> pqmax;
  • 小顶堆:priority_queue<int, vector<int>, greater<int>> pqmin;
  • 高效操作:插入(push)和删除(pop)的时间复杂度为 O(log n),访问队首元素(top)为 O(1)
  • 不支持遍历:内部通过堆实现,直接遍历无法得到有序序列。

常用操作

  • 插入元素pq.push(value);
  • 删除队首pq.pop();
  • 访问队首int top = pq.top();
  • 判空pq.empty()
  • 大小pq.size()

如果想了解更加具体的可以访问cplusplus——priority_queue


♥♥♥本篇博客内容结束,期待与各位优秀程序员交流,有什么问题请私信♥♥♥

♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥

✨✨✨✨✨✨个人主页✨✨✨✨✨✨


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

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

相关文章

Vagrant 安装指南:从零开始搭建开发环境

Vagrant 是一款强大的虚拟化工具&#xff0c;能够帮助开发者快速创建和管理轻量级的、可复制的开发环境。它通过与 VirtualBox、VMware 或 Hyper-V 等虚拟机提供程序结合使用&#xff0c;让你在本地轻松运行虚拟机。本文将详细介绍如何在 Windows、macOS 和 Linux 系统上安装 V…

APIGen-MT:高效生成多轮人机交互Agent数据的两阶段框架

APIGen-MT&#xff1a;高效生成多轮人机交互数据的两阶段框架 引言 随着人工智能技术的飞速发展&#xff0c;AI代理&#xff08;Agent&#xff09;已从简单的聊天机器人发展为能够执行复杂现实任务的系统&#xff0c;例如管理金融交易、安排预约和处理客户服务等。然而&#x…

【NLP】 21. Transformer整体流程概述 Encoder 与 Decoder架构对比

1. Transformer 整体流程概述 Transformer 模型的整个处理流程可以概括为从自注意力&#xff08;Self-Attention&#xff09;到多头注意力&#xff0c;再加上残差连接、层归一化、堆叠多层的结构。其核心思想是利用注意力机制对输入进行并行计算&#xff0c;从而避免传统 RNN …

《Vue Router实战教程》21.扩展 RouterLink

欢迎观看《Vue Router 实战&#xff08;第4版&#xff09;》视频课程 扩展 RouterLink RouterLink 组件提供了足够的 props 来满足大多数基本应用程序的需求&#xff0c;但它并未尝试涵盖所有可能的用例&#xff0c;在某些高级情况下&#xff0c;你可能会发现自己使用了 v-sl…

开发一个答题pk小程序的大致成本是多少

答题 PK 小程序通常指的是一种允许用户之间进行实时或异步答题竞赛的应用程序&#xff0c;可能结合PK答题、积分系统、排行榜等功能。 一、首先&#xff0c;确定答题 PK 小程序的基本功能模块。这可能包括用户注册登录、题库管理、题目类型&#xff08;单选、多选、判断等&am…

GPT-2 语言模型 - 模型训练

本节代码是一个完整的机器学习工作流程&#xff0c;用于训练一个基于GPT-2的语言模型。下面是对这段代码的详细解释&#xff1a; 文件目录如下 1. 初始化和数据准备 设置随机种子 random.seed(1002) 确保结果的可重复性。 定义参数 test_rate 0.2 context_length 128 tes…

科技项目验收测试包括哪些内容?有什么作用?

在现代科技快速发展的背景下&#xff0c;科技项目的验收测试已成为项目管理中的重要环节。科技项目验收测试是一种系统性的方法&#xff0c;旨在评估一个科技项目是否达到预定的技术指标和要求&#xff0c;确认项目的完成质量。该测试通常在项目实施完成后进行&#xff0c;通过…

websoket 学习笔记

目录 基本概念 工作原理 优势 应用场景 HTTP协议与 webSoket协议之间的对比 消息推送场景 1. 轮询&#xff08;Polling&#xff09; 2. 长轮询&#xff08;Long Polling&#xff09; 3. 服务器发送事件&#xff08;Server-Sent Events, SSE&#xff09; 4. WebSocket…

博途 TIA Portal之1200做从站与汇川EASY的TCP通讯

上篇我们写到了博途做主站与汇川EASY的通讯。通讯操作起来很简单,当然所谓的简单,也是相对的,如果操作成功一次,那么后面就很容易了, 如果操作不成功,就会很遭心。本篇我们将1200做从站,与汇川EASY做主站进行TCP的通讯。 1、硬件准备 1200PLC一台,带调试助手的PC机一…

【数据结构_6下篇】有关链表的oj题

思路&#xff1a; 1.分别求出这两个链表的长度 2.创建两个引用&#xff0c;指向两个链表的头节点&#xff1b;找到长度长的链表&#xff0c;让她的引用先走差值步数 3.让这两个引用&#xff0c;同时往后走&#xff0c;每个循环各自走一步 然后再判定两个引用是否指向同一个…

vscode+wsl 运行编译 c++

linux 的 windows 子系统&#xff08;wsl&#xff09;是 windows 的一项功能&#xff0c;可以安装 Linux 的发行版&#xff0c;例如&#xff08;Ubuntu&#xff0c;Kali&#xff0c;Arch Linux&#xff09;等&#xff0c;从而可以直接在 windows 下使用 Linux 应用程序&#xf…

关于 Spring Boot 微服务解决方案的对比,并以 Spring Cloud Alibaba 为例,详细说明其核心组件的使用方式、配置及代码示例

以下是关于 Spring Boot 微服务解决方案的对比&#xff0c;并以 Spring Cloud Alibaba 为例&#xff0c;详细说明其核心组件的使用方式、配置及代码示例&#xff1a; 关于 Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案! https://sca.aliyun.com/?spm7145af80…

VS 基于git工程编译版本自动添加版本号

目录 概要 实现方案 概要 最近在用visual Studio 开发MFC项目时&#xff0c;需要在release版本编译后的exe文件自动追加版本信息。 由于我们用的git工程管理&#xff0c;即需要基于最新的git 提交来打版本。 比如&#xff1a; MFCApplication_V1.0.2_9.exe 由于git 提交信…

pytorch软件封装

封装代码&#xff0c;通过传入文件名&#xff0c;即可输出类别信息 上一章节&#xff0c;我们做了关于动物图像的分类&#xff0c;接下来我们把程序封装&#xff0c;然后进行预测。 单张图片的predict文件 predict.py 按着路径&#xff0c;导入单张图片做预测from torchvis…

【多线程-第四天-自己模拟SDWebImage的下载图片功能-看SDWebImage的Demo Objective-C语言】

一、我们打开之前我们写的异步下载网络图片的项目,把刚刚我们写好的分类拖进来 1.我们这个分类包含哪些文件: 1)HMDownloaderOperation类, 2)HMDownloaderOperationManager类, 3)NSString+Sandbox分类, 4)UIImageView+WebCache分类, 这四个文件吧,把它们拖过来…

电脑提示“找不到mfc140u.dll“的完整解决方案:从原因分析到彻底修复

当你启动某个软件或游戏时&#xff0c;突然遭遇"无法启动程序&#xff0c;因为计算机中丢失mfc140u.dll"的错误提示&#xff0c;这确实令人沮丧。mfc140u.dll是Microsoft Foundation Classes&#xff08;MFC&#xff09;库的重要组成部分&#xff0c;属于Visual C Re…

图像变换方式区别对比(Opencv)

1. 变换示例 import cv2 import matplotlib.pyplot as plotimg cv2.imread(url) img_cut img[100:200, 200:300] img_rsize cv2.resize(img, (50, 50)) (hight,width) img.shape[:2] rotate_matrix cv2.getRotationMatrix2D((hight//2, width//2), 50, 1) img_wa cv2.wa…

图像颜色空间对比(Opencv)

1. 颜色转换 import cv2 import matplotlib.pyplot as plotimg cv2.imread("tmp.jpg") img_r cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_g cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_h cv2.cvtColor(img, cv2.COLOR_BGR2HSV) img_l cv2.cvtColor(img, cv2.C…

每天学一个 Linux 命令(15):man

可访问网站查看,视觉品味拉满:http://www.616vip.cn/15/index.html 每天学一个 Linux 命令(15):man 命令简介 man(Manual)是 Linux 中最核心的命令之一,用于查看命令、系统调用、库函数等的手册文档。它是用户和开发者获取帮助的核心工具,几乎覆盖了系统中的所有功…

必刷算法100题之计算右侧小于当前元素的个数

题目链接 315. 计算右侧小于当前元素的个数 - 力扣&#xff08;LeetCode&#xff09; 题目解析 计算数组里面所有元素右侧比它小的数的个数, 并且组成一个数组,进行返回 算法原理 归并解法(分治) 当前元素的后面, 有多少个比我小(降序) 我们要找到第一比左边小的元素, 这样…