LeetCode从入门到超凡(四)深入浅出理解贪心算法

head-bar

引言

大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的LeetCode学习总结文档;本文主要讲解贪心算法。💕💕😊


介绍

贪心算法是一种经典的算法策略,广泛应用于解决最优化问题。在许多情况下,贪心算法能够以简单且高效的方式解决复杂问题。因此,掌握贪心算法对开发人员和算法爱好者来说非常重要。本文旨在帮助读者深入理解贪心算法的工作原理、特征、正确性证明及其实际应用,并通过多个实例的分析和Python代码实现来巩固理解。

目标读者

本文适合有一定编程基础,尤其是具备基础算法和数据结构知识的读者,旨在帮助这些读者深入理解贪心算法并掌握其应用。


一、贪心算法基础

1. 什么是贪心算法?

贪心算法是一种在每一步选择中都采取当前状态下最优或最有利的选择,从而期望通过局部最优解最终得到全局最优解的算法。

  • 定义:贪心算法是一种逐步构建解的算法,每一步都选择当前看起来最好的局部解决方案,并希望这些局部解决方案的集合能够产生全局最优解。
  • 核心思想:局部最优 -> 全局最优。

2. 贪心算法的特征

uml

贪心算法在使用时需要满足两个特征:

  1. 贪心选择性质:即从局部最优的角度出发,当前的最优选择不依赖于未来的选择。每一步的选择是局部最优解。
  2. 最优子结构:即问题的最优解由其子问题的最优解组成。这意味着问题可以通过递归的方式求解,且子问题的最优解与整个问题的最优解是一致的。

3. 贪心算法的优缺点

  • 优点:简单、高效,通常时间复杂度较低。由于不需要像动态规划那样保存子问题的解,贪心算法的空间复杂度也较低。
  • 缺点:贪心算法不能保证在所有问题上都能找到全局最优解,它只适用于能够满足贪心选择性质和最优子结构性质的问题。选择错误的策略,可能导致非最优解。

二、贪心算法的工作原理

1. 贪心算法的三步走

贪心算法可以通过以下三步来求解问题:

  1. 转换问题:将复杂的问题转换为子问题,使得每一步都有一个明确的最优选择。
  2. 贪心选择性质:在每一步中选择当前最优解,从而构建局部最优解。

  1. 最优子结构性质:将每一步的局部最优解结合起来,最终得到全局最优解。

如果不能利用子问题的最优解推导出整个问题的最优解,那么这种问题就不具有最优子结构。😎

2. 贪心算法的正确性证明

要证明贪心算法能够求解问题的最优解,常用以下两种方法:

  1. 数学归纳法:先计算出边界情况(例如 n=1)的最优解,然后再证明对于每个 n, F n + 1 F_{n + 1} Fn+1 都可以由 F n F_n Fn 推导出。
  2. 交换论证法:从最优解出发,在保证全局最优不变的前提下,如果交换方案中任意两个元素 / 相邻的两个元素后,答案不会变得更好,则可以推定目前的解是最优解。

三、贪心算法的应用实例

接下来作者将通过几个经典问题来演示贪心算法的实际应用,并通过Python代码来解释每个问题的贪心策略。

1.分发饼干问题

问题描述:假设你有若干孩子和若干饼干,每个孩子有一个胃口值,每个饼干有一个尺寸。当且仅当某个饼干的尺寸大于等于某个孩子的胃口值时,该孩子才会得到饼干。你的目标是尽可能满足更多的孩子。

贪心策略优先满足胃口最小的孩子,因为最小的胃口更容易得到满足

代码实现

def find_content_children(g, s):"""分发饼干问题:param g: 孩子的胃口数组:param s: 饼干的尺寸数组:return: 能满足的最大孩子数量"""# 对孩子的胃口和饼干尺寸进行排序g.sort()s.sort()child_i = 0cookie_i = 0# 遍历饼干和孩子,尽量满足更多的孩子while child_i < len(g) and cookie_i < len(s):if s[cookie_i] >= g[child_i]:# 如果当前饼干能满足当前孩子,分发饼干child_i += 1cookie_i += 1  # 无论是否满足孩子,尝试下一个饼干return child_i# 示例
g = [1, 2, 3]
s = [1, 1]
print(find_content_children(g, s))  # 输出: 1
过程分析:
  1. 首先将孩子的胃口数组 g 和饼干尺寸数组 s 排序。
  2. 通过遍历饼干和孩子,尽量让每个饼干满足胃口最小的孩子。
  3. 使用贪心策略,尽可能满足最多的孩子。

2. 无重叠区间问题

问题描述:给定一组区间,找到最少移除的区间数量,使得剩余区间互不重叠。

贪心策略:按结束时间排序,优先选择结束时间最早的区间。

代码实现

def erase_overlap_intervals(intervals):"""无重叠区间问题:param intervals: 区间数组:return: 需要移除的最小区间数量"""if not intervals:return 0# 按区间的结束时间进行排序intervals.sort(key=lambda x: x[1])end = intervals[0][1]count = 0# 遍历所有区间for i in range(1, len(intervals)):if intervals[i][0] < end:# 如果当前区间与前一个区间重叠,则移除count += 1else:# 否则,更新结束时间end = intervals[i][1]return count# 示例
intervals = [[1, 2], [2, 3], [3, 4], [1, 3]]
print(erase_overlap_intervals(intervals))  # 输出: 1
过程分析:
  1. 将区间按照结束时间排序,结束时间越早,后续可选择的空间越大。
  2. 遍历区间,检查当前区间是否与前一个区间重叠,如果重叠则移除当前区间。

3. 柠檬水找零问题

问题描述:你正在卖柠檬水,每位顾客给你 5、10 或 20 美元,你需要找零。假设一开始你没有任何零钱,问你能否在所有顾客完成交易后成功找零。

贪心策略:优先使用大面额的钞票找零。

代码实现

def lemonade_change(bills):"""柠檬水找零问题:param bills: 顾客支付的钞票数组:return: 是否能够找零成功"""five = ten = 0for bill in bills:if bill == 5:five += 1elif bill == 10:if five == 0:return Falsefive -= 1ten += 1else:if ten > 0 and five > 0:ten -= 1five -= 1elif five >= 3:five -= 3else:return Falsereturn True# 示例
bills = [5, 5, 5, 10, 20]
print(lemonade_change(bills))  # 输出: True
过程分析:
  1. 当顾客支付 10 美元时,优先找 5 美元。
  2. 当顾客支付 20 美元时,优先找 10 美元和 5 美元,如果没有 10 美元,则找 3 张 5 美元。
  3. 如果无法找零,返回 False

4. 分发糖果问题

问题描述:给定 N 个孩子,每个孩子有一个评分。你需要按照评分的高低给每个孩子发放糖果,保证评分高的孩子获得更多糖果,要求使用最少的糖果。

贪心策略

两次遍历,分别从左到右和从右到左,确保每个孩子都得到符合规则的糖果。

代码实现

def candy(ratings):"""分发糖果问题:param ratings: 孩子的评分数组:return: 最少的糖果数量"""n = len(ratings)candies = [1] * n# 从左到右遍历for i in range(1, n):if ratings[i] > ratings[i - 1]:candies[i] = candies[i - 1] + 1# 从右到左遍历for i in range(n - 2, -1, -1):if ratings[i] > ratings[i + 1]:candies[i] = max(candies[i], candies[i + 1] + 1)return sum(candies)# 示例
ratings = [1, 0, 2]
print(candy(ratings))  # 输出: 5
过程分析:
  1. 从左到右遍历,确保评分高的孩子获得比左边多的糖果。
  2. 从右到左遍历,确保评分高的孩子获得比右边多的糖果。
  3. 两次遍历后,每个孩子的糖果数量即为最终结果。

四、贪心算法的局限性与扩展

1. 局限性

贪心算法并不总能保证全局最优解。对于某些问题,贪心策略可能导致次优解。下面是一个经典的反例:

  • 反例:最小化硬币找零问题
    在找零问题中,如果贪心地选择面额最大的钱币,可能无法找到最优解。例如,当找零为 14 时,面额为 10、7 和 1 的硬币,贪心算法会选择 10 和 4 个 1 元硬币,而最优解应为两个 7 元硬币。

2. 扩展

  • 动态规划与贪心算法的对比:动态规划通过保存子问题的最优解,能够处理更多复杂的最优化问题,适用于贪心算法不适合的场景。
  • 启发式算法:在某些复杂问题中,启发式算法可以作为贪心算法的扩展,用于近似求解复杂问题。

五、总结

总而言之,贪心算法是一种简单、高效的算法,适用于某些具有贪心选择性质和最优子结构性质的问题。通过几个经典问题的学习和实践,读者可以掌握贪心算法的应用。读者也可以深入学习动态规划、启发式算法等更高级的算法,进一步提升算法能力。😎👌


相关链接

  • 项目地址:LeetCode-CookBook
  • 相关文档:专栏地址
  • 作者主页:GISer Liu-CSDN博客

thank_watch

如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.

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

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

相关文章

《中国电子报》报道: 安宝特AR为产线作业者的“秘密武器

近日&#xff0c;中国电子报在其文章《下一代工业智能终端重新定义制造业》中对安宝特的增强现实&#xff08;AR&#xff09;解决方案给予了高度评价&#xff0c;称其为产线作业者的“秘密武器”。这一创新技术改变了传统制造业的作业方式&#xff0c;使得操作人员能够在生产过…

Java中Map和Set详细介绍,哈希桶的实现

大家好呀&#xff0c;前一节我们接触了二叉搜索树&#xff0c;那么紧接着&#xff0c;我们要学习一种十分重要而且也是我们在初阶数据结构中接触的最后一种数据结构—Map和Set&#xff0c;本篇博客将会详细介绍两种数据结构&#xff0c;并且针对哈希表底层实现一个哈希桶&#…

从0到1深入浅出构建Nest.Js项目

Nest (NestJS) 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的开发框架。它利用JavaScript 的渐进增强的能力&#xff0c;使用并完全支持 TypeScript &#xff08;仍然允许开发者使用纯 JavaScript 进行开发&#xff09;&#xff0c;并结合了 OOP &#xff08;面向对…

Java的学习(语法相关)

字符串存储的问题 char 和字符串都是字符的集合&#xff0c;它们之间的确有相似性&#xff0c;但在 Java 中它们有着不同的存储机制和处理方式。让我从 char 和 String 的本质区别入手来解释。 1. char 和 String 的区别 char 是基本类型&#xff1a;char 是 Java 中的基本数据…

Java-数据结构-Map和Set(三)-习题 o(´^`)o

目录 ❄️一、习题一(只出现一次的数字)&#xff1a; ❄️二、习题二(随机链表的复制)&#xff1a; ❄️三、习题三(宝石与石头)&#xff1a; ❄️四、习题四(旧键盘)&#xff1a; ❄️五、习题五(前k个高频单词)&#xff1a; ❄️总结&#xff1a; ❄️一、习题一(只出现一…

Python(三)——列表

文章目录 创建列表访问下标遍历列表元素新增元素查找元素删除元素连接列表切片操作 创建列表 创建列表主要有两种方式 [ ]表示一个空的列表 a [] print(type(a)) # <class list> print(a) # []通过list()的方式来创建一个空列表 a list() print(type(a)) # …

Java对象头

一、对象在堆内存中的布局 1.定义 在HotSpot虚拟机中&#xff0c;对象在堆内存的存储布局可以划分为三个部分&#xff1a;对象头&#xff08;Header&#xff09;、实例数据&#xff08;Instance Data&#xff09;、和对齐填充&#xff08;Paddin&#xff09;。 二、对象在堆内…

Rstudio:强大的R语言集成开发环境(IDE)

Rstudio 应该是 R 语言使用的标配&#xff0c;尽管 Rstudio 的母公司 Posit 推出了新一代的集成开发环境 Positron&#xff0c;但其还处于开发阶段。作为用户不妨让其成熟后再使用&#xff0c;现阶段还是 Rstudio 更稳定。 如果你在生物信息学或统计学领域工作&#xff0c;R语言…

【springboot】整合沙箱支付

目录 1. 配置沙箱应用环境2. 配置springboot项目1. 引入依赖2. 配置文件注册下载ngrok 3. 创建支付宝支付服务类4. 支付界面模板5. 控制类实现支付6. 测试 1. 配置沙箱应用环境 使用支付宝账号登录到开放平台控制台。 使用支付宝登录后&#xff0c;看到以下页面&#xff0c;下…

动态内存分配

1. 基本使用 在内存空间中&#xff0c;我们如何做到想用多少内存空间就申请多少内存空间&#xff1f; 使用以下函数可以实现&#xff1a; 如何利用malloc申请一片连续的内存空间&#xff1a; int* p malloc(100 * sizef(int)); 该代码实现了&#xff0c;申请一片空间&#…

VS开发 - 静态编译和动态编译的基础实践与混用

目录 1. 基础概念 2. 直观感受一下静态编译和动态编译的体积与依赖项目 3. VS运行时库包含哪些主要文件&#xff08;从VS2015起&#xff09; 4. 动态库和静态库混用的情况 5. 感谢清单 1. 基础概念 所谓的运行时库&#xff08;Runtime Library&#xff09;就是WINDOWS系统…

828华为云征文|WordPress部署

目录 前言 一、环境准备 二、远程连接 三、WordPress简介 四、WordPress安装 1. 基础环境安装 ​编辑 2. WordPress下载与解压 3. 创建站点 4. 数据库配置 总结 前言 WordPress 是一个非常流行的开源内容管理系统&#xff08;Content Management System, CMS&#xf…

进度条(倒计时)Linux

\r回车(回到当前行开头) \n换行 行缓冲区概念 什么现象&#xff1f; 什么现象&#xff1f;&#xff1f; 什么现象&#xff1f;&#xff1f;&#xff1f; 自己总结&#xff1a; #pragma once 防止头文件被重复包含 倒计时 在main.c中&#xff0c;windows.h是不可以用的&…

CleanMyMac X v4.12.1 中文破解版 Mac优化清理工具

在数字时代&#xff0c;我们的Mac设备承载着越来越多的重要信息和日常任务。然而&#xff0c;随着时间的推移&#xff0c;这些设备可能会变得缓慢、混乱&#xff0c;甚至充满不必要的文件。这就是CleanMyMac X发挥作用的地方。 CleanMyMac X是一款功能强大的Mac优化工具&#…

Python 从入门到实战32(数据库MySQL)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了数据库编程接口操作的相关知识。今天我们将学习…

CSP-J Day 3 模拟赛补题报告

姓名&#xff1a;王胤皓&#xff0c;校区&#xff1a;和谐校区&#xff0c;考试时间&#xff1a; 2024 2024 2024 年 10 10 10 月 3 3 3 日 9 : 00 : 00 9:00:00 9:00:00~ 12 : 30 : 00 12:30:00 12:30:00&#xff0c;学号&#xff1a; S 07738 S07738 S07738 请关注作者的…

[20241003] 狂飙500天,国产大模型如何突破商业化之困?

大模型加速狂飙&#xff0c;AI商业化却面临巨大鸿沟。 一方面&#xff0c;传统企业不知道怎么将AI融入原始业务&#xff0c;另一方面&#xff0c;AI企业难以找到合适的变现方式。AI企业究竟该如何突破商业化之困&#xff1f;B端和C端&#xff0c;呈现出两种不同的路径。 纵…

Pikachu-暴力破解-验证码绕过(on client)

访问页面&#xff0c; 从burpsuite 上看到返回的源代码&#xff1b; 验证码生成时通过 createCode 方法生成&#xff0c;在前端页面生成&#xff1b; 同时也是在前端做的校验&#xff1b; 直接验证&#xff1b;F12 -- 网络&#xff0c;随便输入个账号、密码、验证码&#xff0…

OceanBase—02(入门篇——对于单副本单节点,由1个observer扩容为3个observer集群)——之前的记录,当初有的问题未解决,目前新版未尝试

OceanBase—02&#xff08;入门篇——对于单副本单节点&#xff0c;由1个observer扩容为3个observer集群&#xff09;——之前的记录&#xff0c;有的问题未解决&#xff0c;新版未尝试 1、前言—安装单副本单节点集群1.1 docker安装OB 2、查看现有集群情况2.1 进入容器&#x…

计算机网络的整体认识---网络协议,网络传输过程

计算机网络背景 网络发展 独立模式: 计算机之间相互独立; 网络互联: 多台计算机连接在一起, 完成数据共享; 局域网LAN: 计算机数量更多了, 通过交换机和路由器连接在一起; 广域网WAN: 将远隔千里的计算机都连在一起;所谓 "局域网" 和 "广域网" 只是一个相…