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
            //防止在单调平坡上出现error
            preDiff=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;
        
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Vue】分享一个快速入门的前端框架以及如何搭建

先上效果图: 登录 菜单: 下载地址: 链接&#xff1a;https://pan.baidu.com/s/1m-ZlBARWU6_2n8jZil_RAQ 提取码&#xff1a;ui20 … 主要是可以自定义设置token,更改后端请求地址较为方便。 应用设置: 登录与token设置: 在这里设置不用登录,可以请求的接口: request.js i…

jdk8升级JDK21(Springboot2.7.18升级Springboot3.4.0)

目录 背景&#xff1a; 一、maven升级 二、代码改造 2.1 javax替换为jakarta 2.2 swagger2升级swagger3相关更新 2.2.1 新增SpringDocConfig配置类 2.2.2 全局代码更新 2.2.3 全局代码替换&#xff08;普通正则替换&#xff09; 2.3 Mybatis Plus升级 2.4 logback.xm…

数据库(3)--针对列的CRUD操作

1.Create 新增 语法&#xff1a; insert into 表名 &#xff08;列名&#xff09;values &#xff08;列&#xff09;... 创建一个学生表用于演示&#xff1a; create table if not exists student( id bigint comment 编号, name varchar(20) comment 姓名 ); 1.1直接增加…

加速科技荣获“浙江省企业研究院”认定

近日&#xff0c;浙江省经济和信息化厅公布“2024年认定&#xff08;备案&#xff09;省级企业研发机构名单”。经过多轮严格评审和公示&#xff0c;加速科技荣获“省企业研究院”认定。这是加速科技继获国家级专精特新“小巨人”企业认定荣誉后的又一里程碑。 “浙江省企业研究…

leetcode:1784. 检查二进制字符串字段(python3解法)

难度&#xff1a;简单 给你一个二进制字符串 s &#xff0c;该字符串 不含前导零 。 如果 s 包含 零个或一个由连续的 1 组成的字段 &#xff0c;返回 true​​​ 。否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;s "1001" 输出&#xff1a;fa…

双向列表的实现(C++)

一.实现思路 主要是一个空间存储一个数值&#xff0c;然后为了索引后面的数据单元和前面的数据单元&#xff0c;所以在每个空间里面还要存储前面和后面数据单元的指针&#xff0c;就形成了每个数据单元 后面就是要管理的是双向列表的头结点和尾节点&#xff0c;方便实现后面的头…

【前端开发常用网站汇总-01】

1、仿mac界面代码截图 https://codeimg.io/?utm_sourceappinn.com 2、可视化大屏汇总(在线Demo) https://www.xiongze.net/viewdata/index.html 3、在线Photoshop(实现简单P图) https://ps.gaoding.com/#/ 4、在线生成ico图标(png转icon文件) https://www.bitbug.net/in…

腾讯云AI代码助手编程挑战赛-百事一点通

作品简介 百事通问答是一款功能强大的智能问答工具。它依托海量知识储备&#xff0c;无论你是想了解生活窍门、学习难点&#xff0c;还是工作中的专业疑惑&#xff0c;只需输入问题&#xff0c;就能瞬间获得精准解答&#xff0c;以简洁易懂的方式呈现&#xff0c;随时随地为你…

网络安全 信息收集入门

1.信息收集定义 信息收集是指收集有关目标应用程序和系统的相关信息。这些信息可以帮助攻击者了解目标系统的架构、技术实现细节、运行环境、网络拓扑结构、安全措施等方面的信息&#xff0c;以便我们在后续的渗透过程更好的进行。 2.收集方式-主动和被动收集 ①收集方式不同…

Qt QDockWidget详解以及例程

Qt QDockWidget详解以及例程 引言一、基本用法二、深入了解2.1 窗口功能相关2.2 停靠区域限制2.3 在主窗体布局 引言 QDockWidget类提供了一个可以停靠在QMainWindow内的小窗口 (理论上可以在QMainWindow中任意排列)&#xff0c;也可以作为QMainWindow上的顶级窗口浮动 (类似一…

Spring——自动装配

假设一个场景&#xff1a; 一个人&#xff08;Person&#xff09;有一条狗&#xff08;Dog&#xff09;和一只猫(Cat)&#xff0c;狗和猫都会叫&#xff0c;狗叫是“汪汪”&#xff0c;猫叫是“喵喵”&#xff0c;同时人还有一个自己的名字。 将上述场景 抽象出三个实体类&…

MySQL安装,配置教程

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

上手体验微软全新整合的王炸平台Fabric

体验确实不错&#xff0c;微软强大的生态能力。 把可视化&#xff0c;数仓&#xff0c;数据胡&#xff0c;数据工厂&#xff0c;机器学习&#xff0c;数据监控等技术都整合到一个平台了。所有数据全都存储在统一的one lake数据中心&#xff0c;消除数据孤岛问题。而且不同角色可…

LabVIEW调用不定长数组 DLL数组

在使用 LabVIEW 调用 DLL 库函数时&#xff0c;如果函数中的结构体包含不定长数组&#xff0c;直接通过 调用库函数节点&#xff08;Call Library Function Node&#xff09; 调用通常会遇到问题。这是因为 LabVIEW 需要与 DLL 中的数据结构完全匹配&#xff0c;而包含不定长数…

重温设计模式--13、策略模式

策略模式介绍 文章目录 策略模式介绍C 代码示例 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法的行为。该模式将算法的定义和使用分离开来&#xff0c;使得算法可以独立于使用它的客户端而变化&#xff0c;提高了代码的灵活性和可维护性。 其主要包含以下几个…

Bytebase 3.0.1 - 可配置在 SQL 编辑器执行 DDL/DML

&#x1f680; 新功能 新增环境策略&#xff0c;允许在 SQL 编辑器内直接执行 DDL/DML 语句。 支持为 BigQuery 数据脱敏。 在项目下新增数据访问控制及脱敏管理页面。 在数据库页面&#xff0c;支持回滚到变更历史的某个版本。 &#x1f514; 兼容性变更 禁止工单创建…

关机重启后,GitLab服务异常

整理机房,关闭了所有主机重新上架。 上架后开机,所有主机硬件启动正常。 其中一台GitLab服务器启动正常,使用gitlab-ctl status查看服务业正常。 但使用web登陆却失败,如下图: 反复测试,发现无论使用正确密码还是错误密码都是同样的提示。很大可能是数据库的问题。 使…

Python基于YOLOv8和OpenCV实现车道线和车辆检测

使用YOLOv8&#xff08;You Only Look Once&#xff09;和OpenCV实现车道线和车辆检测&#xff0c;目标是创建一个可以检测道路上的车道并识别车辆的系统&#xff0c;并估计它们与摄像头的距离。该项目结合了计算机视觉技术和深度学习物体检测。 1、系统主要功能 车道检测&am…

【算法】查找与排序

因文章篇幅有限&#xff0c;查找和排序分开写&#xff08;附代码与详细过程 注释详解&#xff09;&#xff0c;这篇文章主讲算法中的数据查找。 查找是数据结构中最基本的操作之一&#xff0c;用于从给定的数据集合中找到特定的目标数据。查找的效率直接影响程序的性能&#…

Linux环境中对Postgrel数据库的安装与配置

一、环境准备 linux操作系统的环境是centos7; Postgrel数据库的版本是12.0&#xff0c;不同版本的下载渠道如下&#xff08;PostgreSQL: File Browser&#xff09;&#xff1a; 可以看到压缩包是比较小的&#xff1b;下载之后&#xff0c;上传到你的linux环境中即可。 二、安…