贪心算法+动态规划 | 眼光不同决定深度不同

news2024/12/24 2:31:12

前言

  • 上大学那会有门课程叫做【算法与实践】, 算法配上 C++ 那感觉不要提多爽了。现在回想起来算法不局限于语言,只不过每个语言的语法不一罢了, 但是算法的内在逻辑都是相通的,今天我们通过三个案列来了解分析下算法之一 【贪心算法】。

简介

  • 贪心算法指的是总是能够实现局部最优解。啥意思呢?就是说在每一步场景下选择最优解,不考虑全局是否能够达成最优解。
  • 贪心算法与动态规划与很多相似之处。贪心算法适用的问题也是最优子结构。贪心算法与动态规划有一个显著的区别,就是贪心算法中,是以自顶向下的方式使用最优子结构的。贪心算法会先做选择,在当时看起来是最优的选择,然后再求解一个结果子问题,而不是先寻找子问题的最优解,然后再做选择。
  • 接下来我们通过不同场景来分别体会下,动态规划贪心算法 的区别吧。从而更加深刻的理解 贪心 为何物? 为什么贪心只能实现局部最优解

场景

零钱兑换

题目描述

 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
 ​
 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
 ​
 你可以认为每种硬币的数量是无限的。
复制代码
  • 翻译一下就是:假设1元、2元、5元、10元、20元、50元、100元的金额分别有c0, c1, c2, c3, c4, c5, c6。现在要用这些钱来支付K元,至少要用多少零钱兑换。

解题思路

  • 本题不难发现最好的解法就是 动态规划 。 对于给定的数组中组成K元以来与数组中元素。S(K-1)=1+min(S(k-i))。

例子1:假设

coins = [1, 2, 5], amount = 11 则,当 i==0i==0 时无法用硬币组成,为 0 。当 i<0i<0 时,忽略 F(i)F(i)

F(i) 最小硬币数量 F(0) 0 //金额为0不能由硬币组成 F(1) 1 //F(1)=min(F(1-1),F(1-2),F(1-5))+1=1F(1)=min(F(1−1),F(1−2),F(1−5))+1=1 F(2) 1 //F(2)=min(F(2-1),F(2-2),F(2-5))+1=1F(2)=min(F(2−1),F(2−2),F(2−5))+1=1 F(3) 2 //F(3)=min(F(3-1),F(3-2),F(3-5))+1=2F(3)=min(F(3−1),F(3−2),F(3−5))+1=2 F(4) 2 //F(4)=min(F(4-1),F(4-2),F(4-5))+1=2F(4)=min(F(4−1),F(4−2),F(4−5))+1=2 ... ... F(11) 3 //F(11)=min(F(11-1),F(11-2),F(11-5))+1=3F(11)=min(F(11−1),F(11−2),F(11−5))+1=3 我们可以看到问题的答案是通过子问题的最优解得到的。

AC代码

 public class Solution {
     public int coinChange(int[] coins, int amount) {
         int max = amount + 1;
         int[] dp = new int[amount + 1];
         Arrays.fill(dp, max);
         dp[0] = 0;
         for (int i = 1; i <= amount; i++) {
             for (int j = 0; j < coins.length; j++) {
                 if (coins[j] <= i) {
                     dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                 }
             }
         }
         return dp[amount] > amount ? -1 : dp[amount];
     }
 }
复制代码

玩筹码

题目描述

 有 n 个筹码。第 i 个筹码的位置是 position[i] 。
 ​
 我们需要把所有筹码移到同一个位置。在一步中,我们可以将第 i 个筹码的位置从 position[i] 改变为:
 ​
 position[i] + 2 或 position[i] - 2 ,此时 cost = 0
 position[i] + 1 或 position[i] - 1 ,此时 cost = 1
 返回将所有筹码移动到同一位置上所需要的 最小代价 。
复制代码

解题思路

  • 所谓算法其实也是前人总结出来的经验罢了。初看毫无头绪,再看仍无头绪这就是算法的魅力,当我们知道此题可以通过 贪心 来解决时就有了头绪了。

  • 首先通过题目描述我们能够得处一下结论:

    • 每次仅能移动一个筹码
    • 每次移动范围介于1~2之间
    • 移动2步长,无代价
    • 移动1步长,则付出1代价
  • 移动2步无需付出代价,意味着我们可以将筹码分成两组,组内成员所在位置索引差值皆为 2 。最终只需要考虑哪组需要合并即可。

  • 因为移动两步时无需代价的,则按照上面分组后,组内合并则是无需付出代价的。合并后如下

  • 到了这里我们只需要考虑 A 组移向 B 组 还是 B 组移动到 A 组 。这个判断依据则是看两组谁数量少。因为我们还有一个限制就是每次仅移动一枚筹码。所以数量少的一组移动到数量多的一组,换句话说数量少的一组的数量即为整体的移动代价。

AC代码

 class Solution {
     public int minCostToMoveChips(int[] position) {
         int even = 0, odd = 0;
         for (int pos : position) {
             if ((pos & 1) != 0) {
                 odd++;
             } else {
                 even++;
             }
         }
         return Math.min(odd, even);
     }
 }
复制代码

升级扩展

  • 上面已经可以满足需求了。但是作为企业开发这么多年,早已经习惯了预留扩展功能了。加入之后我们引入新的策略,移动三步代价这时候我们可以这么修改代码
 ​
 public int minCostToMoveChips(int[] position) {
         int step = 2;
         int[] stepArr = new int[step];
         for (int pos : position) {
             int posIndex=pos%step;
             stepArr[posIndex]++;
         }
         int min = stepArr[0];
         for (int i = 1; i < stepArr.length; i++) {
             if (min > stepArr[i]) {
                 min = stepArr[i];
             }
         }
         return min;
     }
复制代码

装箱子

题目描述

 请你将一些箱子装在 一辆卡车 上。给你一个二维数组 boxTypes ,其中 boxTypes[i] = [numberOfBoxesi, numberOfUnitsPerBoxi] :
 ​
 numberOfBoxesi 是类型 i 的箱子的数量。
 numberOfUnitsPerBoxi 是类型 i 每个箱子可以装载的单元数量。
 整数 truckSize 表示卡车上可以装载 箱子 的 最大数量 。只要箱子数量不超过 truckSize ,你就可以选择任意箱子装到卡车上。
 ​
 返回卡车可以装载 单元 的 最大 总数。
 ​
复制代码

解题思路

  • 玩筹码 游戏中可以说是巧妙的运用贪心实现,也许我们并未完全体会到贪心算法的作用。而 装箱子 则是彻彻底底的贪心算法的思路。 零钱兑换 我使用的是 动态规划 ,他的特点是自下而上的流程。上游的结果取决于下游的结果。
  • 贪心算法 中则是 自上而下 , 比如本题中装箱子我们假设 Fx 表示车厢装满X箱子后最大容量。很明显我们只需要每次都选择剩余箱子里容量最大的即可。
  • 从两者选择策略上也可以看得出来,贪心算法仅仅是局部最优解。而不是全局最优解。

AC代码

 class Solution {
     public int maximumUnits(int[][] boxTypes, int truckSize) {
         Arrays.sort(boxTypes, (a, b) -> b[1] - a[1]);
         int res = 0;
         for (int[] boxType : boxTypes) {
             int numberOfBoxes = boxType[0];
             int numberOfUnitsPerBox = boxType[1];
             if (numberOfBoxes < truckSize) {
                 res += numberOfBoxes * numberOfUnitsPerBox;
                 truckSize -= numberOfBoxes;
             } else {
                 res += truckSize * numberOfUnitsPerBox;
                 break;
             }
         }
         return res;
     }
 }
复制代码

总结

1.不能保证求得的最后解是最佳的 2.不能用来求最大值或最小值的问题 3.只能求满足某些约束条件的可行解的范围

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

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

相关文章

显示控件——滑动选择

该控件也是一种调节控件&#xff0c;通过在既定范围内的滑动来选择具体选项值以图达到对变量的调控效果&#xff0c;其UI操作效果类似于拨动密码锁的滚轮。 位置信息&#xff1a;控件在工程页面区域的位置 “X”“Y”为控件区域左上角坐标。 “W”“H”为控件区域宽度和高度&a…

cpu设计和实现(取指)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 cpu设计的本质是数字电路的设计。要是没有verilog、vhdl这些语言&#xff0c;那么剩下来使用的方法基本只有卡诺图这一种了。在数字电路中&#xf…

看懂这篇文章,你就懂了Mybatis的二级缓存

缓存的概述和分类 概述 缓存就是一块内存空间.保存临时数据 为什么使用缓存 将数据源&#xff08;数据库或者文件&#xff09;中的数据读取出来存放到缓存中&#xff0c;再次获取的时候 ,直接从缓存中获取&#xff0c;可以减少和数据库交互的次数,这样可以提升程序的性能&a…

【MySQL】MySQL复制原理与主备一致性同步工作原理解析(原理篇)(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

Qt之天气预报实现(一)预备篇

文章目录序章一、思路整理1.1 我的Qt版本信息1.2 我使用的API二、高德开放平台API的申请和使用2.1 API的申请步骤2.1.1 注册高德开放平台账号&#xff08;若已有账号请无视&#xff09;2.1.2 创建API_KEY2.2 API的使用2.2.1 天气查询文档和城市编码下载位置&#xff08;必读&am…

node版本与node-sass版本不兼容时问题解决

在项目运行中会经常遇到node版本号与node-sass版本号不兼容的问题&#xff0c;这时可以有两种解决方案。 附图&#xff1a;node与node-sass的对应关系 1、改node版本号去对应node-sass 2、改node-sass版本号去对应node 一般情况下选择修改node-sass的版本号&#xff0c;这里…

[附源码]SSM计算机毕业设计茶园认养管理平台JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

PGL图学习之图神经网络GNN模型GCN、GAT[系列六]

PGL图学习之图神经网络GNN模型GCN、GAT[系列六] 项目链接&#xff1a;一键fork直接跑程序 https://aistudio.baidu.com/aistudio/projectdetail/5054122?contributionType1 0.前言-学术界业界论文发表情况 ICLR2023评审情况&#xff1a; ICLR2023的评审结果已经正式发布&a…

OPLSAA力场参数之快速建模—MS+Moltemplate

文章目录一、MS中画出分子结构二、根据OPLSAA力场文件设置原子力场1. OPLSAA力场2. 根据OPLSAA力场中的原子质量进行检查3. 在MS中设置为对应的原子编号三、转换为Lammps可以读取的Data文件四、采用Moltemplate自带工具生成Lt文件1. 生成LT文件2. LT文件结构五、引入OPLSAA力场…

Docker 【Nginx集群部署】

目录 1. nginx前置操作 2. 自定义容器 3. nginx常用命令 4. Error 4.1 502(无响应网关/代理) 4.2 404(找不到对应页面) 4.3 400(异常请求) 4.4 响应超时问题 5. 完整版本Nginx配置文件 1. nginx前置操作 1. 下载拉取nginx镜像 docker pull nginx 2. 使用nginx镜像创…

LVS负载均衡群集(DR模式)

LVS-DR工作原理 数据包流向分析 第一步&#xff1a;客户端发送请求到 Director Server (负载均衡器&#xff09;&#xff0c;请求的数据报文到达内核空间。 数据报文 源 IP ------客户端的 IP 目标 IP ------ VIP 源 MAC ------客户端的 MAC 目的 MAC ------ Director Server…

全产业链核心升级 集聚创新大展宏图——慕尼黑华南电子展回顾

展会简介 2022年11月15日至17日&#xff0c;高交会 - 智能制造、先进电子及激光技术博览会旗下成员展 &#xff08;LEAP Expo&#xff09;-慕尼黑华南电子展、慕尼黑华南电子生产设备展、华南先进激光及加工应用技术展览会及同期举办的华南电路板国际贸易采购博览会与中国&…

【全网热点】打造全网最全爱心代码仓库【火速领取爱心】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 本文章收录于专栏 【代码实践】 目录&#x1f319;正文&#x1f30f;部分效果在线演示&#x1f30f;部分效果截屏&#x1f338;文末祝…

操作系统4小时速成:复习内存管理,内部碎片和外部碎片,页式存储管理,段式存储管理,段页式存储管理,虚拟内存,页面置换算法,LRU内存替换算法

操作系统4小时速成&#xff1a;复习内存管理&#xff0c;内部碎片和外部碎片&#xff0c;页式存储管理&#xff0c;段式存储管理&#xff0c;段页式存储管理&#xff0c;虚拟内存&#xff0c;页面置换算法,LRU内存替换算法 2022找工作是学历、能力和运气的超强结合体&#xff…

react面试题详解

React-Router怎么设置重定向&#xff1f; 使用<Redirect>组件实现路由的重定向&#xff1a; <Switch><Redirect from/users/:id to/users/profile/:id/><Route path/users/profile/:id component{Profile}/> </Switch>当请求 /users/:id 被重定…

显示控件——直线进度条

该控件是指定一个图标&#xff08;矩形长条&#xff09;&#xff0c;通过其滑动在水平方向或者垂直方向实现来调节指定存储空间的变量的效果。滑动范围对应变量地址数据&#xff0c;显示位置通过变量设定。可以配合“滑动调节”触摸控件进行设置。 位置信息&#xff1a;控件在工…

Android App接管手势处理TouchEvnet中单点触摸和多点触控的讲解及实战(附源码 超简单实用)

运行有问题或需要源码请点赞关注收藏后评论区留言~~~ 一、单点触摸 dispatchTouchEvent onInterceptTouchEvent onTouchEvent三个方法的输入参数都是手势事件MotionEvent&#xff0c;其中包含触摸动作的所有信息&#xff0c;各种手势操作都从MotionEvent中获取触摸信息并判断处…

Python3,5行代码,让你拥有无限量壁纸美图,终于告别手动下载了。

这里写目录标题1、引言2、代码实战2.1 手动下载2.2 代码批量下载3、总结1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 你电脑桌面壁纸挺好看啊。 小鱼&#xff1a;那是&#xff0c; 毕竟我的审美观在这摆着呢。 小屌丝&#xff1a;你这话&#xff0c;让我不服… 小鱼&#xff…

STC51单片机30——单个数码管显示

#include<reg51.h> // 包含51单片机寄存器定义的头文件 /************************************************** 函数功能&#xff1a;延时函数&#xff0c;延时一段时间 ***************************************************/ void delay(void) { unsigned …

腾讯二面vue面试题总结

Vue2.x 响应式数据原理 整体思路是数据劫持观察者模式 对象内部通过 defineReactive 方法&#xff0c;使用 Object.defineProperty 来劫持各个属性的 setter、getter&#xff08;只会劫持已经存在的属性&#xff09;&#xff0c;数组则是通过重写数组7个方法来实现。当页面使…