当前位置: 首页 > news >正文

贪心策略实战Leetcode 860题:柠檬水找零问题的优雅解法

贪心策略实战Leetcode 860题:柠檬水找零问题的优雅解法

  • 📌 问题背景:一场贴近生活的算法考验
  • 🧠 算法原理:贪心策略的核心逻辑拆解
    • 核心思想
    • 找零的逻辑分析
    • 📊 算法步骤可视化(流程图)
  • 💻 C++代码实现:简洁高效的贪心解法
    • 核心代码
    • 代码详解
    • 性能分析
  • 📝 算法总结与拓展
    • 柠檬水找零问题的核心收获
    • 贪心算法的拓展场景
  • 🌟 写在最后

✨ 前言:在算法的世界里,贪心策略就像一把精巧的钥匙,总能以最直观、最高效的方式打开一类最优化问题的大门。它不追求复杂的全局推导,而是立足当下做出最优选择,最终收获全局的正确解。今天我们就以LeetCode 860题——柠檬水找零问题为例,拆解贪心策略的核心思想,用C++实现简洁高效的解题代码,带你感受贪心算法的独特魅力~

📌 问题背景:一场贴近生活的算法考验

我们化身街头柠檬水摊主,开启一天的摆摊之旅,却遇到了一个现实的问题:出摊时手上没有任何零钱,柠檬水定价为5元/杯,前来购买的顾客会随机支付5元、10元或20元的纸币,我们需要判断能否为每一位顾客顺利找零,让交易无间断完成。

这个问题看似是日常的找零场景,实则是典型的贪心算法应用案例,没有复杂的逻辑嵌套,核心在于每一次找零都做出对后续最有利的选择,这也是贪心策略的精髓所在。

🧠 算法原理:贪心策略的核心逻辑拆解

核心思想

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。区别于动态规划的全局规划,贪心的关键是局部最优选择能推导出全局最优解,而柠檬水找零问题恰好满足这一特性。

找零的逻辑分析

柠檬水单价5元,顾客支付面额仅为5、10、20元,我们只需维护手中5元、10元、20元纸币的数量(20元纸币仅作为收入,无法用于找零,核心关注5和10元),针对不同支付面额制定专属找零策略:

  1. 顾客支付5元:无需找零,直接增加手中5元纸币的数量即可;

  2. 顾客支付10元:需要找零5元,仅能使用5元纸币找零。若手中有5元则完成找零(5元数量-1,10元数量+1),若无则无法找零,返回false;

  3. 顾客支付20元:需要找零15元,有两种找零方案:

    • 方案1:1张10元 + 1张5元(优先选择)

    • 方案2:3张5元

    贪心选择的关键:为什么优先选10+5的组合?因为5元纸币是找零的“通用货币”,10元仅能用于20元的找零,而5元可用于10元和20元的找零。保留更多的5元纸币,能为后续更多的找零场景提供支持,这就是局部最优选择,最终实现全局的找零成功。

📊 算法步骤可视化(流程图)

开始 | v 初始化:count5=0,count10=0,count20=0 | v 遍历每位顾客的支付金额cash | |---- cash ==5 → count5++ → 继续遍历 | |---- cash ==10 → 判断count5>0? | | | |--- 是 → count5--,count10++ → 继续遍历 | |--- 否 → 返回false(找零失败) | |---- cash ==20 → 先判断count10>0且count5>0? | |--- 是 → count10--,count5--,count20++ → 继续遍历 |--- 否 → 判断count5>=3? | |--- 是 → count5-=3,count20++ → 继续遍历 |--- 否 → 返回false(找零失败) | v 所有顾客遍历完成 → 返回true(全部找零成功) 结束

💻 C++代码实现:简洁高效的贪心解法

核心代码

基于上述逻辑,我们用C++实现代码,代码仅需一次遍历(时间复杂度O(n)),常数级额外空间(空间复杂度O(1)),满足题目最优性能要求:

#include <iostream> #include <vector> using namespace std; // 柠檬水找零核心函数 bool lemonadeChange(vector<int>& bills) { int count5 = 0, count10 = 0, count20 = 0; // 记录三种纸币的数量 for (int cash : bills) { if (cash == 5) { // 支付5元,无需找零 count5++; } else if (cash == 10) { // 支付10元,需找5元 if (count5 == 0) return false; count5--; count10++; } else { // 支付20元,优先10+5找零 if (count10 > 0 && count5 > 0) { count10--; count5--; } else if (count5 >= 3) { // 无10元,用3张5元找零 count5 -= 3; } else { // 两种方案都不可行,找零失败 return false; } count20++; // 20元数量仅记录,不参与找零 } } // 所有顾客都完成找零 return true; } // 测试主函数 int main() { vector<int> test1 = {5,5,5,10,20}; // 测试用例1:找零成功 vector<int> test2 = {5,5,10,10,20}; // 测试用例2:找零失败 cout << "测试用例1结果:" << (lemonadeChange(test1) ? "成功" : "失败") << endl; cout << "测试用例2结果:" << (lemonadeChange(test2) ? "成功" : "失败") << endl; return 0; }

代码详解

  1. 变量初始化:定义count5count10count20三个整型变量,初始值为0,分别记录手中5、10、20元纸币的数量;

  2. 遍历支付数组:用范围for循环遍历顾客的支付金额数组bills,对每一个支付面额做分支处理;

  3. 分支逻辑:严格遵循上述贪心找零策略,对5、10、20元分别处理,一旦发现无法找零,立即返回false

  4. 测试用例:主函数中设置两个典型测试用例,分别验证找零成功和失败的场景,直观展示函数功能。

性能分析

  • 时间复杂度:O(n),其中n为顾客的数量,代码仅对支付数组做一次线性遍历,无嵌套循环;

  • 空间复杂度:O(1),仅使用了三个整型变量记录纸币数量,额外空间与输入规模无关,为常数级。

📝 算法总结与拓展

柠檬水找零问题的核心收获

  1. 贪心策略的适用前提:局部最优选择能推导出全局最优解,本题中“优先保留5元纸币”的局部选择,能最大化后续找零的可能性,最终实现全局找零成功;

  2. 问题简化技巧:将实际问题抽象为算法模型,忽略无关细节(如柠檬水的成本、利润),聚焦核心矛盾(找零的面额匹配);

  3. 代码设计原则:基于贪心的算法实现往往简洁高效,无需复杂的数据结构,仅通过基础变量和分支判断即可完成。

贪心算法的拓展场景

贪心策略并非万能,但在很多经典问题中都能发挥奇效,例如:

  • 零钱兑换(特定面额下的最优解);

  • 活动选择问题(选择最多的不重叠活动);

  • 哈夫曼编码(最优前缀编码);

  • 跳跃游戏(判断能否到达数组末尾)。

解决这类问题的关键,是找到问题的贪心选择性质,即确定“每一步该如何选择才能让结果最优”。

🌟 写在最后

柠檬水找零问题作为贪心算法的入门经典题,让我们感受到了算法与生活的紧密结合,也体会到了贪心策略“化繁为简”的魅力。算法的学习并非死记硬背,而是理解其核心思想,将其运用到实际问题中。

这道题的讲解告一段落,后续我们还会继续拆解煎饼排序等经典算法问题,探索更多算法思想的实战应用~ 关注我,一起在算法的世界里稳步前行,解锁更多高效解题技巧!💪

http://www.jsqmd.com/news/509260/

相关文章:

  • Lychee模型量化实战:8倍压缩下的精度保持策略
  • Mirage Flow 目标检测应用升级:从YOLOv8到YOLOv11的模型辅助优化
  • Qwen3-32B-Chat新手必看入门指南:无需CUDA编译经验的私有大模型部署
  • 2026年消防维修服务选择指南:五大专业机构深度解析与场景化选型建议 - 2026年企业推荐榜
  • 破局与新生:2026年九龙坡地区离婚律师专业服务五强解析 - 2026年企业推荐榜
  • Wan2.1-umt5跨平台部署体验:对比不同操作系统的配置差异
  • Dify多Agent任务编排失效的8种隐性征兆,运维总监都在偷偷检查的3个埋点指标
  • Qwen3-32B编程助手体验:代码生成与调试,开发者神器
  • 【RL】Deep Research Agent 训练经验探索
  • 空间变革新纪元:2026年济南调光玻璃供应商的深度选择与未来展望 - 2026年企业推荐榜
  • 【华为OD机试真题】任务编排系统 · 双任务时长组合问题(Python/JS)
  • MCP4261数字电位器驱动库:SPI通信、EEPROM存储与嵌入式应用
  • Kinova机械臂远程操控新玩法:用GRU-VAE模型实现手势到动作的秒级转换
  • Snipe-IT:开源IT资产管理系统的创新实践指南
  • 惊艳效果:UNIT-00自动生成Python数据分析完整脚本与报告
  • 2026高端装修新风向:深度测评五家引领“制造型半包”趋势的实力服务商 - 2026年企业推荐榜
  • SSVXYMatrix:嵌入式XY坐标LED矩阵驱动框架
  • Qwen-Image-2512-SDNQ WebUI用户体验优化:进度条动画+生成耗时预估提示
  • Shadow Sound Hunter与SolidWorks集成:智能设计辅助
  • Stable Diffusion XL 1.0镜像免配置优势:灵感画廊预装diffusers 0.27+优化版本
  • Mathtype公式编辑与AI结合:百川2-13B辅助识别与生成数学公式
  • 【华为OD机试真题】任务编排系统 · 双任务时长组合问题(C语言)
  • 2026年自动封口机选购指南:五大信誉厂家深度解析与推荐 - 2026年企业推荐榜
  • P8651 [蓝桥杯 2017 省 B] 日期问题【日期计算+排序】
  • Cosmos-Reason1-7B部署案例:消费级GPU(RTX 4090/3090)FP16高效推理
  • RT-Thread线程管理:动态/静态创建与生命周期控制
  • 2026长沙推拿足浴消费指南:五大品牌深度解析与选购建议 - 2026年企业推荐榜
  • 2026年温州休闲运动鞋制造深度解析:五家做工精湛的实力厂家横向评测 - 2026年企业推荐榜
  • 银河麒麟系统下Miniconda安装避坑指南:解决Permission denied错误
  • 轻量级嵌入式任务调度框架cola_os设计与实践