Javascript算法——贪心算法(一)

贪心算法详解(JavaScript)(局部最优->全局最优)

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取当前状态下的最优选择(局部最优)的算法设计方法。通过局部最优解的累积,试图最终达到全局最优解。尽管贪心算法并不总能保证得到最优解,但它对某些问题(如优化类问题)非常有效。

贪心算法的核心思想
  1. 问题分解:将问题分解成多个子问题。
  2. 贪心选择性质:对每个子问题,做出一个局部最优选择。
  3. 无后效性:当前的选择不会影响后续的决策,或者即使受到影响,也不会导致最优解的丢失。
  4. 重复上述步骤:直到所有子问题解决。
贪心算法的实现步骤
  1. 分析问题是否适合贪心:问题是否满足贪心选择性质和无后效性。
  2. 构造贪心策略:确定如何在每一步选择局部最优解。
  3. 验证贪心策略的正确性:证明或推导出贪心策略能够得到问题的最优解。
  4. 实现代码:利用循环、排序、优先队列等工具编写代码。

经典贪心算法案例及实现

案例 1:分发饼干

问题描述
有两组数据,分别是孩子的胃口数组 g 和饼干大小数组 s。每个孩子只能吃一个饼干,只有当饼干的大小 ≥ 孩子的胃口时,该饼干才能满足该孩子。求最多有多少孩子可以满足。

贪心思路

  1. 将孩子的胃口和饼干大小排序。
  2. 每次将最小的饼干分配给最小胃口的孩子(局部最优)。
  3. 如果当前饼干不能满足孩子,则尝试下一块饼干。

代码实现

function findContentChildren(g, s) {// 排序胃口和饼干大小g.sort((a, b) => a - b);s.sort((a, b) => a - b);let child = 0;let cookie = 0;while (child < g.length && cookie < s.length) {if (s[cookie] >= g[child]) {// 当前饼干可以满足当前孩子child++;}// 尝试分配下一块饼干cookie++;}return child;
}// 示例
console.log(findContentChildren([1, 2, 3], [1, 1])); // 输出: 1
console.log(findContentChildren([1, 2], [1, 2, 3])); // 输出: 2

案例 2:跳跃游戏

问题描述
给定一个非负整数数组,每个元素表示你在该位置最多能跳多远。判断是否可以从数组的第一个位置跳到最后一个位置。

贪心思路

  1. 维护一个变量 maxReach 表示当前能够到达的最远位置。
  2. 遍历数组:
    • 如果当前索引大于 maxReach,则无法跳到当前位置。
    • 否则更新 maxReach 为当前索引加上跳跃步数。
  3. 如果遍历结束时 maxReach 大于等于数组最后一个位置,则说明可以到达。

代码实现

function canJump(nums) {let maxReach = 0;for (let i = 0; i < nums.length; i++) {if (i > maxReach) {// 当前索引无法到达return false;}maxReach = Math.max(maxReach, i + nums[i]);}return true;
}// 示例
console.log(canJump([2, 3, 1, 1, 4])); // 输出: true
console.log(canJump([3, 2, 1, 0, 4])); // 输出: false

案例 3:区间调度问题

问题描述
给定多个区间,求最多能选择不重叠的区间数量。

贪心思路

  1. 按照区间的结束时间升序排序(局部最优:优先选择结束时间最早的区间)。
  2. 遍历区间列表,每次选择当前区间与上一次选择的区间不重叠的区间。

代码实现

function intervalSchedule(intervals) {if (intervals.length === 0) return 0;// 按结束时间升序排序intervals.sort((a, b) => a[1] - b[1]);let count = 1; // 至少有一个区间被选中let end = intervals[0][1];for (let i = 1; i < intervals.length; i++) {if (intervals[i][0] >= end) {// 当前区间与上一个区间不重叠count++;end = intervals[i][1];}}return count;
}// 示例
console.log(intervalSchedule([[1, 3], [2, 4], [3, 5]])); // 输出: 2
console.log(intervalSchedule([[1, 2], [2, 3], [3, 4], [1, 3]])); // 输出: 3

贪心算法的优缺点

优点

  • 简单高效:解决问题的步骤清晰,易于实现。
  • 局部最优:很多时候可以快速找到接近最优的解。

缺点

  • 适用性有限:不适用于所有问题,特别是需要全局视野的问题。
  • 无法回溯:一旦做出选择,就不能回退检查其他可能性。

贪心算法适用场景

  1. 贪心选择性质:整体最优解可以通过一系列局部最优解构成
  2. 无后效性:某一步的决策不会影响后续步骤的最优性。

常见的适用问题包括:最小生成树(Prim、Kruskal 算法)、最短路径问题(Dijkstra 算法)、区间调度、活动选择等。

希望这些内容对你理解和使用贪心算法有所帮助! 😊

贪心算法vs动态规划算法

贪心算法与动态规划算法的比较详解

贪心算法和动态规划是两种常用的算法设计方法,它们各自适用于不同类型的问题,主要区别在于解决问题的思路和适用场景。以下是两者的详细比较:


1. 核心思想
方面贪心算法动态规划
基本思路每一步都选择当前状态下的局部最优解。将问题分解成多个子问题,利用子问题的解构造全局最优解。
全局性通过局部最优推导全局最优解。通过递推式逐步解决子问题以达到全局最优解。

2. 适用问题
方面贪心算法动态规划
问题类型适用于具有贪心选择性质和无后效性的优化问题。适用于有重叠子问题和最优子结构性质的问题。
典型问题活动选择、最小生成树、最短路径(Dijkstra)。背包问题、最长公共子序列、最长递增子序列。

3. 实现复杂度
方面贪心算法动态规划
实现难度相对简单,直接选择当前最优解即可。需要设计状态、递推关系和表格存储。
时间复杂度通常为 ( O(n \log n) ) 或 ( O(n) )。通常为 ( O(n^2) ) 或更高。
空间复杂度一般为 ( O(1) )。需要额外的存储空间(例如表格),通常为 ( O(n^2) )。

4. 解决过程
方面贪心算法动态规划
过程描述通过排序、优先队列等工具选择局部最优。使用状态转移方程递推计算,通常自底向上。
回溯性无法回溯,一旦选择即固定。可以通过存储子问题结果进行回溯。

5. 优势与局限性
方面贪心算法动态规划
优势高效、简单,适用于实时计算。可以保证得到全局最优解。
局限性不保证全局最优解,适用问题较少。复杂度较高,消耗更多的时间和空间资源。

贪心算法与动态规划的对比表格总结

属性贪心算法动态规划
选择方式每一步选择局部最优解依赖子问题结果,通过递推求解全局最优解
适用问题特性贪心选择性质、无后效性重叠子问题、最优子结构
时间复杂度通常较低通常较高
空间复杂度通常为 ( O(1) )需要额外存储,通常为 ( O(n^2) )
实现难度简单,逻辑清晰需要设计状态转移方程,难度较高
回溯性不可回溯可通过记录表格结果回溯
保证最优解不一定(除非证明问题适合贪心)一定能保证最优解
典型应用活动选择、最小生成树、最短路径背包问题、最长公共子序列、斐波那契数列

两种算法的使用场景总结

  1. 贪心算法

    • 问题适合贪心选择,且有无后效性。
    • 需要快速计算的近似解或简单解。
    • 例子:找零问题、最小生成树、区间调度。
  2. 动态规划

    • 问题有重叠子问题和最优子结构。
    • 不确定贪心是否适用,但需要保证最优解。
    • 例子:背包问题、最长公共子序列、股票买卖问题。

总结:贪心算法和动态规划在解决问题时各有侧重。对于简单、高效的场景可以优先考虑贪心算法,而对于复杂、全局优化的问题则更适合动态规划。

摆动序列

在这里插入图片描述
在这里插入图片描述

核心:考虑这三种情况!!!

在这里插入图片描述
在这里插入图片描述

/*** @param {number[]} nums* @return {number}*/
var wiggleMaxLength = function(nums) {// let len=nums.length;// let strLen=0;// let preDiff=0,curDiff=0,count=0;// //判断字符序列是否为长度,是偶数的话// //还需比较最后两个数组的大小是否大于0// let flag=nums.length%2;// for(let i=0,j=1;j<nums.length;i++,j++){//     curDiff=nums[j]-nums[i];//     if(preDiff>0&&curDiff<0){//         count++;//     }//     if(j===nums.length-1&&!flag&&curDiff>0){//         strLen=count>=1?2*count+2:2;//     }else{//         strLen=count>=1?2*count+1:2;//     }//     preDiff=curDiff;// }// return  strLen;//考虑平坡、单调平坡和收尾元素//默认尾部元素有个坡//preDiff=0可起到前方有个和开始元素值一样的虚拟元素if(nums.length<=1)return nums.length;let preDiff=0,curDiff=0,res=1;//i<nums.length-1  默认尾部元素有个坡for(let i=0;i<nums.length-1;i++){curDiff=nums[i+1]-nums[i];if((curDiff>0&&preDiff<=0)||(curDiff<0&&preDiff>=0)){res++;//在这赋值curDiff,表示只有坡度方向变化时才更新preDiff//防止在单调平坡上出现errorpreDiff=curDiff;}}return res;
};

最大子序列和

在这里插入图片描述
在这里插入图片描述

核心:怎样用代码重新开始位置,其实此题返回值,直接将前面累加和赋值0就行! if(curSum<0)curSum=0;

/*** @param {number[]} nums* @return {number}*/
var maxSubArray = function(nums) {// let res=-Infinity;let res=[];for(let i=0;i<nums.length;i++){curSum+=nums[i];if(curSum>res)res=curSum;//!!!核心,更换起始位置就是把当前curSum赋值为0就行!if(curSum<0)curSum=0;}return res; // for(let i=0;i<nums.length;i++){//     let curSum=0;//     for(let j=i;j<nums.length;j++){//         curSum+=nums[j];//         res.push(curSum);//     }// }// let maxArr=res.sort((a,b)=>b-a)[0];// return maxArr;};

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

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

相关文章

[读书日志]从零开始学习Chisel 第九篇:Scala的内建控制结构(敏捷硬件开发语言Chisel与数字系统设计)

6.Scala的内建控制结构 6.1 if表达式 和大部分编程语言的if表达式使用上没有区别&#xff0c;单句话不需要加花括号&#xff0c;多个语句需要加花括号&#xff0c;直接来看一段代码&#xff1a; scala> def whichInt(x:Int) {| if(x 0) "Zero"| else if(x &g…

AI大模型-提示工程学习笔记5

卷首语&#xff1a;我所知的是我自己非常无知&#xff0c;所以我要不断学习。 写给AI入行比较晚的小白们&#xff08;比如我自己&#xff09;看的&#xff0c;大神可以直接路过无视了。 零提示是什么 “零提示”&#xff08;Zero-shot&#xff09;是指在没有提供任何特定示例…

全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之循环结构(while循环应用)

在 C 编程的世界里&#xff0c;循环结构是掌控程序流程的关键工具之一&#xff0c;而while循环更是其中的经典。它就像一个不知疲倦的小卫士&#xff0c;只要条件满足&#xff0c;就会持续执行特定的代码块&#xff0c;可以解决诸多复杂的编程任务。本文就一同深入探索while循环…

CK18——肝损伤无创诊断标志物

肝脏作为人体至关重要的代谢与解毒器官&#xff0c;极易遭受病毒、药物、酒精及不良饮食等多种因素的损害&#xff0c;进而引发一系列如非酒精性脂肪肝&#xff08;NAFLD&#xff09;、肝纤维化、肝硬化、肝细胞癌以及各类肝炎等病症。因此&#xff0c;确定一种高可靠性、非侵入…

.NET Core + Kafka 开发指南

什么是Kafka Apache Kafka是一个分布式流处理平台,由LinkedIn开发并开源,后来成为Apache软件基金会的顶级项目。Kafka主要用于构建实时数据管道和流式应用程序。 Kafka 架构 从下面3张架构图中可以看出Kafka Server 实际扮演的是Broker的角色, 一个Kafka Cluster由多个Bro…

软件体系结构与设计模式

在软件开发中&#xff0c;软件体系结构和设计模式是两个至关重要的概念。它们帮助开发者设计出易于理解、可扩展、可维护的系统。尽管这两个概念密切相关&#xff0c;但它们分别关注系统的不同方面&#xff1a;软件体系结构关注的是系统整体结构的设计&#xff0c;而设计模式则…

[离线数仓] 总结二、Hive数仓分层开发

接 [离线数仓] 总结一、数据采集 5.8 数仓开发之ODS层 ODS层的设计要点如下: (1)ODS层的表结构设计依托于从业务系统同步过来的数据结构。 (2)ODS层要保存全部历史数据,故其压缩格式应选择压缩比率,较高的,此处选择gzip。 CompressedStorage - Apache Hive - Apac…

Unity3D仿星露谷物语开发19之库存栏丢弃及交互道具

1、目标 从库存栏中把道具拖到游戏场景中&#xff0c;库存栏中道具数相应做减法或者删除道具。同时在库存栏中可以交换两个道具的位置。 2、UIInventorySlot设置Raycast属性 在UIInventorySlot中&#xff0c;我们只希望最外层的UIInventorySlot响应Raycast&#xff0c;他下面…

阿里云代理商热销产品推荐

在数字化浪潮的推动下&#xff0c;企业对于云计算的依赖日益加深。阿里云&#xff0c;作为中国领先的云计算服务提供商&#xff0c;为企业提供了丰富多样的云产品和服务。本文将聚焦于阿里云代理商热销产品推荐&#xff0c;探讨其如何帮助企业高效利用云资源&#xff0c;加速数…

Python入门教程 —— 多任务

1.线程 1.1.线程安全问题 线程访问全局变量 import threading g_num = 0 def test(n):global g_numfor x in range(n):g_num += xg_num -= xprint(g_num)if __name__ == __main__:t1 = threading.Thread(target=test, args=(10,))t2 = threading.Thread(target=test, args=(…

江科大STM32入门——IIC通信笔记总结

wx&#xff1a;嵌入式工程师成长日记 &#xff08;一&#xff09;简介 STM32内部集成了硬件I2C收发电路&#xff0c;可以由硬件自动执行时钟生成、起始终止条件生成、应答位收发、数据收发等功能&#xff0c;减轻CPU的负担 支持多主机 支持7位/10位地址模式 支持不同的通讯速…

vue3 vite 动态加载路由遇到的问题

记录一下动态加载路由遇到的问题 正常使用import引入静态路由是没问题的 component: () > import(/components/ExampleComponent.vue)动态引入的时候写成import就不行了 由于后端给的路由格式比较反人类…我这边先递归把获取到的数据格式做了一个整合. const processedDa…

MySQL安装,配置教程

一、Linux在线yum仓库安装 打开MySQL官方首页&#xff0c;链接为&#xff1a;https://www.mysql.com/ 界面如下&#xff1a; 在该页面中找到【DOWNOADS】选项卡&#xff0c;点击进入下载页面。 在下载界面中&#xff0c;可以看到不同版本的下载链接&#xff0c;这里选择【My…

Elixir语言的面向对象编程

Elixir语言的面向对象编程探讨 引言 Elixir是一种基于Erlang虚拟机的函数式编程语言&#xff0c;旨在支持可扩展性和维护性。尽管Elixir的核心特性是函数式编程模型&#xff0c;但它依然能够实现面向对象编程&#xff08;OOP&#xff09;的某些特性。本文将深入探讨如何在Eli…

【工具】HTML自动识别用户正在讲话 以及停止讲话

【工具】HTML自动识别用户正在讲话 以及停止讲话 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>语…

HTML5 滑动效果(Slide In/Out)详解

HTML5 滑动效果&#xff08;Slide In/Out&#xff09;详解 滑动效果&#xff08;Slide In/Out&#xff09;是一种常见的动画效果&#xff0c;使元素从一侧滑入或滑出&#xff0c;增强页面的动态感和用户体验。以下是滑动效果的详细介绍及实现示例。 1. 滑动效果的特点 动态视…

面试题: 对象继承的方式有哪些

在 JavaScript 中&#xff0c;对象继承可以通过多种方式实现。每种方法都有其特点和适用场景。以下是几种常见的对象继承方式&#xff1a; 1. 原型链继承&#xff08;Prototype Chain Inheritance&#xff09; 这是最基础的对象继承方式&#xff0c;利用了 JavaScript 的原型…

React路由拦截器详解

在React中&#xff0c;路由拦截器是一种机制&#xff0c;用于在导航到特定路由之前执行一些逻辑&#xff0c;比如权限校验、用户认证或动态路由控制。通常&#xff0c;React使用react-router-dom库来管理路由&#xff0c;通过<Routes>和<Route>定义路由规则。 实现…

力扣经典题目之219. 存在重复元素 II

今天继续给大家分享一道力扣的做题心得今天这道题目是 219. 存在重复元素 II&#xff0c;我使用 hashmap 的方法来解题 题目如下&#xff0c;题目链接&#xff1a;219. 存在重复元素 II 1&#xff0c;题目分析 此题目给我们了一个整数数组 nums 和一个整数 k &#xff0c;需要…

四、VSCODE 使用GIT插件

VSCODE 使用GIT插件 一下载git插件与git Graph插件二、git插件使用三、文件提交到远程仓库四、git Graph插件 一下载git插件与git Graph插件 二、git插件使用 git插件一般VSCode自带了git&#xff0c;就是左边栏目的图标 在下载git软件后vscode的git插件会自动识别当前项目 …