【数据结构】贪心算法:决策的艺术
贪心算法(Greedy Algorithm)是一类在每一步选择中都采取局部最优解的方法,希望最终能够达到全局最优解。通俗地说,贪心算法的思想就是“每一步都尽量做出最好的选择”,以期望整个过程的最终结果也达到最优状态。贪心算法在解决某些特定问题时可以提供快速且高效的方案,因此广泛应用于路径选择、调度、资源分配等领域。
贪心算法的工作原理
-
局部最优选择
贪心算法的核心在于每一步选择中做出局部最优的决策。例如,在路径规划问题中,贪心算法会在每一步选择离当前点最近的未访问节点,以试图最小化总距离。虽然每步都采取局部最优,但在整个问题中不一定总能保证最终解是全局最优。因此,贪心算法适合某些特定问题,而不是所有优化问题。
-
不回溯原则
贪心算法一旦做出选择,就不会对之前的选择进行更改。这意味着贪心算法无法“回头”检查先前的步骤,而是坚定不移地继续前进。这一特点使得贪心算法计算速度快,但也意味着在某些情况下可能会错过更优解。
-
适用条件
贪心算法并不适合所有问题,特别是对于某些需要回溯或组合的情况而言效果较差。它适用于那些可以通过局部最优解不断接近全局最优解的问题,如:
- 最短路径问题
- 活动选择问题
- 背包问题
- 区间调度问题
算法实战:找零问题
假设我们需要找零的金额为 amount,并且我们有一些面值的硬币。贪心算法的目标是尽可能少地使用硬币来找零。我们将从面值最大的硬币开始找零。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 找零函数
int coinChange(vector<int>& coins, int amount) {sort(coins.rbegin(), coins.rend()); // 从大到小排序int count = 0;for (int coin : coins) {while (amount >= coin) { // 当金额大于或等于硬币面值时amount -= coin; // 减去硬币面值count++; // 记录使用的硬币数量}}return amount == 0 ? count : -1; // 如果找零成功,返回硬币数量,否则返回-1
}int main() {vector<int> coins = {25, 10, 5, 1}; // 硬币面值int amount = 63; // 要找的金额int result = coinChange(coins, amount);if (result != -1) {cout << "最少需要使用的硬币数量: " << result << endl;} else {cout << "无法找零" << endl;}return 0;
}
实践中的挑战与扩展
虽然贪心算法在找零问题中表现出色,但并非所有硬币组合都能保证找到最优解。例如,若面值为 3 和 4 的硬币用于找零 6,贪心算法可能选择 4 + 3,而最优解为 3 + 3。这种情况下,动态规划将更适合解决问题,因为它能考虑所有可能的组合。
但通过动态规划解决的找零问题会考虑所有组合,确保最终解为全局最优。
如果不清除什么是动态规划的话可以去看我另外一篇文章
- 【数据结构】动态规划:揭开算法优化的秘密
#include <iostream>
#include <vector>
#include <climits>
using namespace std;int coinChangeDP(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);dp[0] = 0; // 基础情况for (int coin : coins) {for (int x = coin; x <= amount; x++) {if (dp[x - coin] != INT_MAX) {dp[x] = min(dp[x], dp[x - coin] + 1);}}}return dp[amount] == INT_MAX ? -1 : dp[amount];
}
贪心算法的优缺点
优点
- 高效:贪心算法的时间复杂度通常较低,在需要快速求解的情况下尤为适合。
- 实现简单:贪心算法的逻辑清晰,易于实现。它只需一步一步地做出决策,不需要复杂的回溯操作。
- 适用于动态数据:在许多实时计算中,贪心算法可以处理不断变化的数据,因为它只关心当前的最佳选择。
缺点
- 不能保证全局最优:贪心算法不能保证所有问题的最优解,有时会因局部选择导致全局次优解。
- 缺乏灵活性:贪心算法无法回溯,也不适合多步决策或组合问题。
- 适用范围有限:贪心算法主要适用于具有贪心选择性质和最优子结构性质的问题。
时空复杂度
如果不清除什么是时空复杂度的话可以去看我另外一篇文章
- 【数据结构】时间复杂度和空间复杂度是什么?
时间复杂度
贪心算法的时间复杂度通常依赖于具体问题和实现方式。一般来说,它的时间复杂度可以通过以下几个方面进行分析:
-
排序:许多贪心算法需要对输入数据进行排序,例如在找零问题中,我们对硬币面值进行了排序。排序的时间复杂度为 ( O ( n log n ) (O(n \log n) (O(nlogn),其中 ( n ) (n) (n) 是输入数据的规模。
-
遍历:贪心算法通常需要遍历输入数据,选择当前的最佳解。这个过程的时间复杂度通常为 (O(n)) 或 (O(m)),其中 (m) 是选定的子问题规模。
综合考虑,贪心算法的时间复杂度通常为 ( O ( n log n ) ) (O(n \log n)) (O(nlogn)) 或 ( O ( n ) ) (O(n)) (O(n)),具体取决于是否需要排序以及遍历的复杂性。
空间复杂度
贪心算法的空间复杂度通常较低,因为它通常不需要额外的存储空间来存储中间结果。常见的空间复杂度为:
-
输入数据存储:需要存储输入数据,时间复杂度与输入规模成正比,空间复杂度为 (O(n))。
-
常量空间:在大多数贪心算法中,只需使用常量空间来保存临时变量和结果,因此其额外空间复杂度通常为 (O(1))。
因此,贪心算法的空间复杂度一般为 (O(n)),但在许多情况下,其有效空间复杂度为 (O(1))。
复杂度总结
| 复杂度类型 | 复杂度表达式 | 说明 |
|---|---|---|
| 时间复杂度 | ( O ( n log n ) ) (O(n \log n)) (O(nlogn)) 或 ( O ( n ) ) (O(n)) (O(n)) | 取决于排序和遍历的复杂性 |
| 空间复杂度 | ( O ( n ) ) (O(n)) (O(n)) 或 ( O ( 1 ) ) (O(1)) (O(1)) | 通常只需常量空间或输入空间 |
通过对时空复杂度的分析,我们可以更好地理解贪心算法的性能表现,并在实际应用中做出合理的选择。
常见应用
-
最短路径问题
在图算法中,Dijkstra算法就是一种基于贪心策略的算法,用来找到从起点到目标节点的最短路径。该算法在每一步选择当前节点的最短边,从而逐步构建最短路径。Dijkstra算法在权值非负的情况下非常有效,但在权值为负的情况下可能无法得到最优解。
-
活动选择问题
活动选择问题是典型的贪心算法应用之一。在一组互不相容的活动中,贪心算法可以帮助选择出最多的活动。例如,若有一组活动需要在不同时间段进行,使用贪心算法可以按活动的结束时间从早到晚排序,依次选择不冲突的活动,从而最大化活动数量。
-
分数背包问题
在背包问题中,贪心算法可用于求解“分数背包问题”,即物品可以按任意比例选择。贪心算法在此问题中选择单位重量价值最高的物品直到背包装满,从而实现价值最大化。
-
区间调度问题
区间调度问题是一种经典的贪心算法应用,它需要从一组区间中选择互不重叠的最大数量。贪心算法的策略是首先选择结束时间最早的区间,以便为后续区间腾出时间,从而实现最大化选择。
如何判断贪心算法是否适用?
在选择是否应用贪心算法时,通常需要满足以下两个条件:
- 贪心选择性质:即可以通过局部最优解一步步获得全局最优解。
- 最优子结构:问题可以通过子问题的最优解构建得到全局最优解。
如果问题不符合这两个条件,那么贪心算法可能不适用,可以考虑动态规划或回溯等更复杂的算法。
贪心算法与动态规划的区别
虽然贪心算法和动态规划都用于解决优化问题,但两者的策略截然不同。动态规划通过记忆化存储和子问题分解来保证全局最优解,而贪心算法则在每一步选择中追求最优。一般而言,当问题具有“贪心选择性质”和“最优子结构”时,贪心算法才适用;否则,动态规划可能是更好的选择。
贪心算法的实现步骤
在实际应用中,贪心算法的实现通常可以分为以下几步:
- 选择贪心策略:定义每一步的选择标准,确保每次选择局部最优。
- 构建选择序列:基于贪心策略逐步构建问题的解答。
- 验证全局解的可行性:确保贪心选择不会影响整体解的正确性。
- 执行选择:按照贪心策略选择直到获得最终解。
总结
贪心算法是一种高效、简便的算法,在特定条件下可以迅速求解最优问题。然而,贪心算法并非万全之策,适用于具有贪心选择性质和最优子结构的问题。它的应用领域广泛,涉及路径规划、活动选择、资源分配等多个方面。在选择是否使用贪心算法时,需要全面分析问题特点,确保其满足贪心算法的适用条件。
相关文章:
【数据结构】贪心算法:决策的艺术
贪心算法(Greedy Algorithm)是一类在每一步选择中都采取局部最优解的方法,希望最终能够达到全局最优解。通俗地说,贪心算法的思想就是“每一步都尽量做出最好的选择”,以期望整个过程的最终结果也达到最优状态。贪心算…...
Linux LVS详解
LVS(Linux Virtual Server)即Linux虚拟服务器,是一个基于Linux操作系统的高性能、可扩展的负载均衡器。以下是对LVS的详细介绍: 一、简介 LVS项目由章文嵩博士在1998年5月发起,是中国国内最早出现的自由软件项目之一…...
LabVIEW显微镜自动对焦系统
在生物医学研究中,显微镜图像的清晰度对于细胞分析非常重要。传统的手动对焦方法容易受到人为因素的影响,因此开发了一种自动对焦技术,以提高图像采集的准确性和效率。 自动对焦方法概述 该系统结合了图像清晰度评估和一维功能优化ÿ…...
基于IP的真实地址生成器
ip-geoaddress-generator 是一个基于 Web 的在线应用程序,能够根据 IP 地址生成真实的随机地址信息。通过多个 API 获取位置数据和随机用户信息,该工具为用户提供了完整的虚拟身份。它由 Next.js 和 Radix UI 构建,具备自动检测当前 IP 地址和…...
下面程序头的三个import语句可以合并或简化么?
下面程序头的三个import语句可以合并或简化么? from tkinter.simpledialog import askinteger from tkinter import * from tkinter import messagebox ——是的,三个import语句可以合并为一个。 合并后的import语句如下所示: from tkinte…...
深度学习--CNN实现猫狗识别二分类(附带下载链接, 长期有效)
1. 代码实现(包含流程解释) 样本量: 8005 # # 1.导入数据集(加载图片)数据预处理# 进行图像增强, 通过对图像的旋转 ,缩放,剪切变换, 翻转, 平移等一系列操作来生成新样本, 进而增加样本容量, # 同时对图片数值进行归一化[0:1] from tensorflow.keras.preprocessing.image …...
Depcheck——专门用于检测 JavaScript 和 Node.js 项目中未使用依赖项的工具
文章目录 Depcheck 是什麽核心功能📚检测未使用的依赖🐛检测缺失的依赖✨支持多种文件类型🌍可扩展性 安装与使用1. 安装 Depcheck2. 使用 Depcheck Depcheck 的应用总结项目源码: Depcheck 是什麽 来看一个常见错误场景…...
前端构建工具vite的优势
1. 极速冷启动 Vite 使用原生 ES 模块 (ESM) 在开发环境下进行工作。相比于传统构建工具需要打包所有的文件,Vite 只在浏览器请求模块时动态加载所需的文件。无打包冷启动:无需预先打包,项目启动非常快,尤其对于大型项目效果更明…...
hive查询语句
1.基本语法 SELECT [ALL | DISTINCT]select_expr, select_expr, ... FROM table_reference [WHERE where_condition] [GROUP BYcol_list] [HAVING where_condition] [ORDER BYcol_list] [CLUSTER BYcol_list | [DISTRIBUTE BY col_list] [SORT BY col_list] ] [LIMIT number] …...
【AIGC】2024-ECCV-ControlNet++:通过有效的一致性反馈改进条件控制
2024-ECCV-ControlNet: Improving Conditional Controls with Efficient Consistency Feedback ControlNet:通过有效的一致性反馈改进条件控制摘要1. 引言2. 相关工作2.1 基于扩散的生成模型2.2 可控的文本到图像扩散模型2.3 语言和视觉奖励模型 3. 方法3.1. 初步3.…...
Mysql5.7变为GreatSQL 8.0.32-25过程中,SQL语句报错及解决方案
考虑兼容国产化数据库,现需要将Mysql5.7变为GreatSQL,在执行部分sql时,发现在Mysql5.7无报错,在GreatSQL有报错,在此记录一下遇到的几个错误。 1.ERROR 1231 (NO_AUTO_CREATE_USER) 1.1.报错提示 ERROR 1231 (42000…...
Qt 使用QAxObject将QTableView数据导出到Excel表格
这是我记录Qt学习过程的第6篇心得文章,主要是方便自己编写的应用程序导出Excel数据的,走了不少弯路直接上代码。 实现代码: //人员信息导出 ui->pbtn2->setEnabled(false); // 打开文件对话框,选择 excel文件 QString fil…...
fastGpt
参考本地部署FastGPT使用在线大语言模型 1 rockylinx 1 ollama安装 在rockylinux中安装的,ollama由1.5G,还是比较大,所有采用在windows下下载,然后安装的方式,linux安装 tar -C /usr -xzf ollama-linux-amd64.tgz #…...
如何全方位应对服务可用性的挑战
在数字化转型的浪潮中,运维团队正站在企业IT架构的核心位置,面对着前所未有的挑战。服务响应时间和失败率,作为衡量服务质量的重要指标,一直备受关注。然而,在追求这两项指标优化的同时,运维团队还需关注其…...
二进制方式部署k8s集群
目标任务: 1、Kubernetes集群部署架构规划 2、部署Etcd数据库集群 3、在Node节点安装Docker 4、部署Flannel网络插件 5、在Master节点部署组件(api-server,schduler,controller-manager) 6、在Node节点部署组件(kubelet,kube-proxy) 7、查看集群状态 8、运行⼀个测…...
Vivado时序报告七:Report Clock NetworkReport Clock Interaction详解
目录 一、前言 二、Report Clock Network 2.1 Report Clock Network流程 2.2 Report Clock Network报告 三、Report Clock Interaction 3.1 示例设计 3.2 配置选项 3.2.1 Options 3.2.2 Timer_Settings 3.3 Clock Interaction报告 3.3.1 Clock Pair Classification …...
HarmonyOS 组件样式@Style 、 @Extend、自定义扩展(AttributeModifier、AttributeUpdater)
1. HarmonyOS Style 、 Extend、自定义扩展(AttributeModifier、AttributeUpdater) Styles装饰器:定义组件重用样式 ;Extend装饰器:定义扩展组件样式 自定义扩展:AttributeModifier、AttributeUpdater 1.1. 区…...
信息安全工程师(73)网络安全风险评估过程
一、确定评估目标 此阶段需要明确评估的范围、目标和要求。评估目标通常包括特定的网络系统、信息系统或网络基础设施,评估范围可能涉及整个组织或仅特定部门。明确评估要求有助于确保评估过程的针对性和有效性。 二、收集信息 在评估开始之前,需要对目标…...
在MacOS玩RPG游戏 - RPGViewerPlus
背景知识 由于我一直使用Mac电脑,所以一直对Mac如何玩RPGMV/RPGMZ游戏的方式有进一步的想法。 网上能给出的方案都是自行启动一个HTTP服务进行,进行服务加载。这个方法有效,但兼容性较差。涉及到自定义功能模块的游戏,都会有报错…...
2024.10.27 直接插入排序 非递归后序遍历(复杂版)
直接插入排序 思路:用temp变量存放需要插入前面有序序列的变量,然后用里面的那个for循环寻找到需要插入的位置。 额外注意的点:arr[j1]temp;这个是因为内置循环每次出来之后所指向的位置是我们要插入的位置的前一个(-1或者插入…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!
多连接 BLE 怎么设计服务不会乱?分层思维来救场! 作者按: 你是不是也遇到过 BLE 多连接时,调试现场像网吧“掉线风暴”? 温度传感器连上了,心率带丢了;一边 OTA 更新,一边通知卡壳。…...
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.
这个警告表明您在使用Vue的esm-bundler构建版本时,未明确定义编译时特性标志。以下是详细解释和解决方案: 问题原因: 该标志是Vue 3.4引入的编译时特性标志,用于控制生产环境下SSR水合不匹配错误的详细报告1使用esm-bundler…...
