贪心算法,其优缺点是什么?
什么是贪心算法?
贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最优(局部最优)的选择,从而希望导致全局最优解的算法策略。
它不像动态规划那样考虑所有可能的子问题,而是做出局部最优选择,依赖这些选择来达到全局最优。
// 经典的找零钱问题 - 贪心算法解法
function coinChange(coins, amount) {// 将硬币面额按从大到小排序coins.sort((a, b) => b - a);let count = 0;let remaining = amount;const result = [];for (const coin of coins) {// 尽可能多地使用当前最大面额while (remaining >= coin) {remaining -= coin;count++;result.push(coin);}if (remaining === 0) break;}return remaining === 0 ? { count, coins: result } : -1;
}// 示例:用[25, 10, 5, 1]美分的硬币找零63美分
console.log(coinChange([25, 10, 5, 1], 63));
// 输出: { count: 6, coins: [25, 25, 10, 1, 1, 1] }
贪心算法的优点
- 高效性:贪心算法通常时间复杂度较低,因为它不需要考虑所有可能的解
- 实现简单:相比动态规划,贪心算法的实现通常更直观和简单
- 空间复杂度低:通常只需要常数或线性额外空间
// 区间调度问题 - 选择最多的不重叠区间
function maxNonOverlappingIntervals(intervals) {if (intervals.length === 0) return 0;// 按结束时间排序intervals.sort((a, b) => a[1] - b[1]);let count = 1;let lastEnd = intervals[0][1];for (let i = 1; i < intervals.length; i++) {const [start, end] = intervals[i];// 如果当前区间开始时间大于等于上一个区间的结束时间if (start >= lastEnd) {count++;lastEnd = end;}}return count;
}// 示例
console.log(maxNonOverlappingIntervals([[1,3], [2,4], [3,6], [5,7]]));
// 输出: 2 (选择[1,3]和[5,7])
贪心算法的缺点
- 不能保证全局最优:贪心算法可能陷入局部最优而非全局最优
- 适用场景有限:只有问题具有贪心选择性质时才适用
- 难以证明正确性:需要数学证明贪心选择确实能得到最优解
// 贪心算法在找零钱问题中的局限
console.log(coinChange([10, 7, 1], 14));
// 贪心输出: { count: 5, coins: [10, 1, 1, 1, 1] }
// 实际最优解: { count: 2, coins: [7, 7] }
// 这里贪心算法没有找到最优解
前端开发中的适用场景
1. 资源加载优先级
// 使用贪心算法确定资源加载顺序
function prioritizeResources(resources) {// 按"重要性/大小"比率排序,优先加载高优先级的资源return resources.map(res => ({...res,priorityScore: res.importance / res.size})).sort((a, b) => b.priorityScore - a.priorityScore).map(res => res.url);
}// 示例
const resources = [{ url: 'critical.css', importance: 10, size: 5 },{ url: 'main.js', importance: 8, size: 20 },{ url: 'hero-image.jpg', importance: 7, size: 50 },{ url: 'analytics.js', importance: 3, size: 15 }
];console.log(prioritizeResources(resources));
// 输出: ["critical.css", "main.js", "hero-image.jpg", "analytics.js"]
2. 任务调度
// 贪心算法实现的任务调度器
class TaskScheduler {constructor() {this.tasks = [];}addTask(task) {this.tasks.push(task);}// 按截止时间排序(最早截止时间优先)scheduleByDeadline() {return [...this.tasks].sort((a, b) => a.deadline - b.deadline);}// 按价值密度排序(价值/时间比高优先)scheduleByValueDensity() {return [...this.tasks].sort((a, b) => {const aDensity = a.value / a.duration;const bDensity = b.value / b.duration;return bDensity - aDensity;});}
}// 示例
const scheduler = new TaskScheduler();
scheduler.addTask({ id: 1, name: 'UI Bug Fix', duration: 2, deadline: 5, value: 3 });
scheduler.addTask({ id: 2, name: 'Feature A', duration: 5, deadline: 10, value: 8 });
scheduler.addTask({ id: 3, name: 'Critical Hotfix', duration: 1, deadline: 2, value: 10 });console.log('By deadline:', scheduler.scheduleByDeadline());
console.log('By value density:', scheduler.scheduleByValueDensity());
3. 响应式布局中的元素排列
// 贪心算法实现简单的响应式布局
function greedyLayout(items, containerWidth) {let currentRow = [];let currentWidth = 0;const result = [];// 按宽度排序(从大到小)items.sort((a, b) => b.width - a.width);for (const item of items) {if (currentWidth + item.width <= containerWidth) {currentRow.push(item);currentWidth += item.width;} else {result.push([...currentRow]);currentRow = [item];currentWidth = item.width;}}if (currentRow.length > 0) {result.push(currentRow);}return result;
}// 示例
const elements = [{ id: 1, width: 200 },{ id: 2, width: 150 },{ id: 3, width: 300 },{ id: 4, width: 100 },{ id: 5, width: 250 }
];console.log(greedyLayout(elements, 500));
/* 输出:
[[{id: 3, width: 300}, {id: 1, width: 200}],[{id: 5, width: 250}, {id: 2, width: 150}, {id: 4, width: 100}]
]
*/
使用建议与注意事项
- 验证贪心选择性质:在使用贪心算法前,确保问题具有贪心选择性质
// 验证是否可以贪心解决的辅助函数
function canUseGreedy(problem) {// 这里应该有具体的验证逻辑// 通常需要检查:// 1. 问题是否具有最优子结构// 2. 局部最优是否能导致全局最优// 3. 是否有反例证明贪心不适用// 伪代码逻辑const hasOptimalSubstructure = checkOptimalSubstructure(problem);const hasGreedyProperty = checkGreedyProperty(problem);const noCounterExamples = checkCounterExamples(problem);return hasOptimalSubstructure && hasGreedyProperty && noCounterExamples;
}
- 与动态规划对比:当贪心算法无法得到最优解时,考虑动态规划
// 找零钱的动态规划解法(对比贪心解法)
function coinChangeDP(coins, amount) {// dp[i]表示组成金额i所需的最少硬币数const dp = new Array(amount + 1).fill(Infinity);dp[0] = 0;for (let i = 1; i <= amount; i++) {for (const coin of coins) {if (coin <= i) {dp[i] = Math.min(dp[i], dp[i - coin] + 1);}}}return dp[amount] === Infinity ? -1 : dp[amount];
}console.log(coinChangeDP([10, 7, 1], 14)); // 输出: 2 (正确解)
- 性能与正确性的权衡:在正确性要求不高但性能要求高的场景可考虑贪心算法
// 大规模数据下的近似排序 - 牺牲一定准确性换取性能
function approximateSortLargeData(data, compareFn, sampleSize = 1000) {// 1. 采样const samples = [];for (let i = 0; i < sampleSize; i++) {samples.push(data[Math.floor(Math.random() * data.length)]);}// 2. 对样本排序samples.sort(compareFn);// 3. 贪心地将元素插入到样本形成的区间中const result = [];for (const item of data) {let inserted = false;for (let i = 0; i < samples.length; i++) {if (compareFn(item, samples[i]) <= 0) {result.splice(i, 0, item);inserted = true;break;}}if (!inserted) result.push(item);}return result;
}
- 前端特定场景的优化:在浏览器环境中,贪心算法可以减少计算时间,提升用户体验
// 使用贪心算法优化DOM操作批量处理
function batchDOMUpdates(elements, updateFn, batchSize = 10) {// 按元素重要性(如可见性、位置等)排序elements.sort((a, b) => {const aRect = a.getBoundingClientRect();const bRect = b.getBoundingClientRect();// 优先处理视口内或接近视口的元素return (aRect.top - bRect.top) || (aRect.left - bRect.left);});// 分批处理for (let i = 0; i < elements.length; i += batchSize) {const batch = elements.slice(i, i + batchSize);// 使用requestAnimationFrame避免阻塞主线程requestAnimationFrame(() => {batch.forEach(el => updateFn(el));});}
}// 使用示例
const allImages = document.querySelectorAll('img');
batchDOMUpdates(Array.from(allImages), img => {img.src = img.dataset.src; // 懒加载
});
贪心算法在前端开发中有着广泛的应用场景,从资源加载优化到任务调度,再到UI布局等方面都能发挥作用。
理解贪心算法的核心思想并能在适当场景中应用它,可以显著提升应用性能。然而,必须谨慎使用,确保问题确实适合贪心策略,避免因局部最优而导致整体解决方案的缺陷。
在实际开发中,我建议:
- 对于性能敏感但正确性要求相对宽松的场景优先考虑贪心算法
- 对于关键功能或正确性要求高的场景,先用贪心算法快速实现,再考虑是否需要更精确的算法
- 在前端优化中,将贪心算法与浏览器API(如requestAnimationFrame、requestIdleCallback)结合使用
- 建立完善的性能监控,验证贪心算法在实际应用中的效果
通过合理运用贪心算法,前端开发者可以在保证用户体验的同时,构建出更高效、响应更快的Web应用。
相关文章:
贪心算法,其优缺点是什么?
什么是贪心算法? 贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最优(局部最优)的选择,从而希望导致全局最优解的算法策略。 它不像动态规划那样考虑所有可能的子问题,而是做出局部最优选择,依赖这些选择来…...
java知识梳理(二)
一.lambda表达式 作用:Lambda 表达式在 Java 8 引入,主要用于简化匿名内部类的写法,特别是在函数式编程场景中,比如 函数式接口、流式 API(Streams)、并发编程等。它让 Java 代码更简洁、可读性更强&#x…...
鸿蒙Flutter实战:20. Flutter集成高德地图,同层渲染
本文以同层渲染为例,介绍如何集成高德地图 完整代码见 Flutter 鸿蒙版 Demo 概述 Dart 侧 核心代码如下,通过 OhosView 来承载原生视图 OhosView(viewType: com.shaohushuo.app/customView,onPlatformViewCreated: _onPlatformViewCreated,creation…...
c++中%符号使用的注意事项/易错点
在C中,% 是取模运算符(modulus operator),用于计算两个数相除后的余数。虽然它的用法看起来简单,但在实际编程中有一些需要注意的细节和易错点。以下是关键注意事项: 1. 操作数必须为整数类型 % 只能用于整…...
AI辅助下基于ArcGIS Pro的SWAT模型全流程高效建模实践与深度进阶应用
目前,流域水资源和水生态问题逐渐成为制约社会经济和环境可持续发展的重要因素。SWAT模型是一种基于物理机制的分布式流域水文与生态模拟模型,能够对流域的水循环过程、污染物迁移等过程进行精细模拟和量化分析。SWAT模型目前广泛应用于流域水文过程研究…...
Java 基础-30-单例设计模式:懒汉式与饿汉式
在软件开发中,单例设计模式(Singleton Design Pattern)是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于管理共享资源(如数据库连接池、线程池等)或需要…...
尚语翻译图册翻译|专业图册翻译|北京专业翻译公司推荐|专业文件翻译报价
内容概要 尚语翻译公司聚焦多语种产品图册翻译的竞价推广服务,通过行业垂直化运营构建差异化竞争力。其核心服务覆盖机械制造、医疗器械、电子元件三大领域,依托ISO 17100认证的翻译流程和Trados术语管理系统,实现技术文档的精准转化。为提升…...
杂篇-行业分类一二-2(通、专用设备制造,汽车制造)
接上篇, 本篇列举制造业中另外几个细分行业:通用设备制造,专用设备制造,汽车制造业。 一、通用设备制造 分类 序号 类别名称 说明 1 锅炉及原动设备制造 1 锅炉及辅助设备制造 指各种蒸汽锅炉、汽化锅炉,以及…...
[笔记.AI]大模型训练 与 向量值 的关系
(借助 DeepSeek-V3 辅助生成) 大模型在训练后是否会改变向量化的值,取决于模型的训练阶段和使用方式。以下是详细分析: 1. 预训练阶段:向量化值必然改变 动态调整过程: 在预训练阶段(如BERT、…...
LeetCode 解题思路 30(Hot 100)
解题思路: 递归参数: 生成括号的对数 n、结果集 result、当前路径 path、左括号数 open、右括号数 close。递归过程: 当当前路径 path 的长度等于 n * 2 时,说明已经生成有效括号,加入结果集。若左括号数小于 n&…...
Java EE(18)——网络原理——应用层HTTP协议
一.初识HTTP协议 HTTP(HyperText Transfer Protocol,超文本传输协议)是用于在客户端(如浏览器)和服务器之间传输超媒体文档(如HTML)的应用层协议。 HTTP协议发展至今发布了多个版本,其中1.0,1.…...
强大而易用的JSON在线处理工具
强大而易用的JSON在线处理工具:程序员的得力助手 在当今的软件开发世界中,JSON(JavaScript Object Notation)已经成为了数据交换的通用语言。无论是前端还是后端开发,我们都经常需要处理、验证和转换JSON数据。今天&a…...
Qt笔记----》不同环境程序打包
文章目录 概要1、windows环境下打包qt程序2、linux环境下打包qt程序2.1、程序目录2.2、创建一个空文件夹2.3、添加依赖脚本2.4、打包过程2.4.1、添加程序依赖库2.4.2、添加Qt相关依赖库 概要 qt不同运行环境下打包方式:windows/linux 1、windows环境下打包qt程序 …...
企业服务器备份软件,企业服务器备份的方法有哪些?
企业服务器备份需综合考虑数据量、业务连续性要求(RTO/RPO)、合规性及成本等因素。以下是分场景的工具和方法指南: 一、备份软件推荐 1. 80KM备份软件 80KM备份软件可以进行很复杂的备份方式,也可以内网对内网备份、还能内网的…...
Vue3 表单
Vue3 表单 随着前端技术的发展,Vue.js 作为一款流行的前端框架,不断更新迭代,以适应更高效、更便捷的开发需求。Vue3 作为 Vue.js 的第三个主要版本,引入了许多新特性和改进,其中包括对表单处理机制的优化。本文将深入探讨 Vue3 表单的使用方法、技巧以及注意事项。 1. …...
html5炫酷图片悬停效果实现详解
html5炫酷图片悬停效果实现详解 这里写目录标题 html5炫酷图片悬停效果实现详解项目介绍技术栈核心功能实现1. 页面布局2. 图片容器样式3. 炫酷悬停效果缩放效果倾斜效果模糊效果旋转效果 4. 悬停文字效果5. 性能优化6. 响应式设计 项目亮点总结 项目介绍 本文将详细介绍如何使…...
安徽京准:GPS北斗卫星校时服务器助力大数据云计算
安徽京准:GPS北斗卫星校时服务器助力大数据云计算 安徽京准:GPS北斗卫星校时服务器助力大数据云计算 GPS北斗卫星校时服务器在大数据与云计算系统中发挥着关键作用,其通过提供高精度、高可靠的时间同步服务,解决了分布式系统的核…...
【Linux】内核驱动学习笔记(二)
7、framebuffer驱动详解 7.1、什么是framebuffer (1)裸机中如何操作LCD (2)OS下操作LCD的难点 (3)framebuffer帧缓冲(简称fb)是linux内核中虚拟出的一个设备 (4)framebuffer向应用层提供一个统一标准接口的显示设备 (5)从驱动来看,fb是一个…...
机器学习的一百个概念(5)数据增强
前言 本文隶属于专栏《机器学习的一百个概念》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见[《机器学习的一百个概念》 ima 知识库 知识库广场搜索&…...
在MCU工程中优化CPU工作效率的几种方法
在嵌入式系统开发中,优化 CPU 工作效率对于提升系统性能、降低功耗、提高实时性至关重要。Keil 作为主流的嵌入式开发工具,提供了多种优化策略,包括 关键字使用、内存管理、字节对齐、算法优化 等。本文将从多个方面介绍如何在 Keil 工程中优…...
优化程序命名:提升专业感与用户体验
在软件开发的广阔天地中,程序命名这一环节常常被开发者们忽视。不少程序沿用着简单直白、缺乏雕琢的名字,如同素面朝天的璞玉,虽不影响其核心功能的发挥,但却在无形之中错失了许多提升用户印象与拓展应用场景的机会。今天…...
美团民宿 mtgsig 小程序 mtgsig1.2 分析
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向分析 cp execjs.compile(open(民…...
短视频团队架构工作流程---2025.3.30 李劭卓
短视频团队架构&工作流程—2025.3.30 李劭卓 文章目录 短视频团队架构&工作流程---2025.3.30 李劭卓1 工作职责1.1 编剧:1.2 主编:1.3 总编:1.4 导演:1.5 摄影:1.6 演员:1.7 后期:1.8 美…...
es 集群存储字典 json字段----python实现
本人的意思是value为json格式数据,而不是简单的如下这种:这种我就没有必要写个博文,肯定是复杂的情况啊。 from elasticsearch import Elasticsearch import json# 创建Elasticsearch客户端 es = Elasticsearch([{host: localhost, port: 9200}])# 定义要存储的字典 my_dic…...
(done) MIT6.824 Lecture 02 - RPC and Threads
知乎专栏:https://zhuanlan.zhihu.com/p/641105196 原视频:https://www.bilibili.com/video/BV16f4y1z7kn?spm_id_from333.788.videopod.episodes&vd_source7a1a0bc74158c6993c7355c5490fc600&p2 看知乎专栏 一、Why we choose go?…...
软件工程面试题(二十四)
1、连接池的原理 j2ee 服务器启动时会建立一定数量的池连接,并一直维持不少于此数量的池连接。当客户端程序需要连接时,吃驱动程序会返回一个未使用的池连接并将其标记为忙。如果当前 没有空闲连接,池驱动就建立一定新的 连接 2、用javascript编写脚本小程序,实现点击全选…...
LayaAir3.3.0-beta.3重磅更新!Spine4.2、2D物理、UI系统、TileMap等全面升级!
正式版推出前,说明3.3的功能还没开发完。所以,又一大波更新来了~ 下面对重点更新进行说明。 Spine的重要更新 3.3.0-beta.3版本开始,新增了Spine 4.2 的运行时库,Spine动画上可以支持物理特性了。例如,下图右侧女孩在启…...
【AI学习】机器学习算法
1,线性回归模型(Linear Regression):预测连续数值 寻找自变量(解释变量)与因变量(被解释变量)之间的线性关联关系,通过构建线性方程来对数据进行拟合和预测。即两个变量之间是一次函…...
【渗透测试】Vulnhub靶机-FSoft Challenges VM: 1-详细通关教程
下载地址:https://www.vulnhub.com/entry/fsoft-challenges-vm-1,402/ 目录 前言 信息收集 目录扫描 wpscan扫描 修改密码 反弹shell 提权 思路总结 前言 开始前注意靶机简介,当第一次开机时会报apache错误,所以要等一分钟后重启才…...
【区块链+ 房产建筑】山东省建筑产业互联网平台 | FISCO BCOS 应用案例
山东省建筑产业互联网平台(山东省弘商易盟平台)是基于区块链技术构建的分布式产业互联网平台, 旨在把各企业内部的供应链协同管理系统(包括采购或者SRM 系统, 以及销售或CRM 系统)利用区块链技术链接起来&a…...
