👩🏻‍💻算法系统学习-老板找零,别找那么多张(贪心算法)

359 阅读5分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。

前言

👩🏻‍💻 该系列是基于有一定语言基础(C,C++,Java等等)和基本的数据结构基础进行的算法学习专栏,如果觉得有点吃力 😥 ,建议先了解前提知识再学习喔!本个专栏会将用更容易理解的表达去学习算法,如果在一些表述上存在问题还请各位多多指点 🧑🏻‍🚀 ,要是觉得还不错记得点个 👍本专栏快捷门:juejin.cn/column/7024…

贪心算法

基本概念:

又称贪婪算法,登山算法,根本思想是逐步到达山顶,即逐步获得最优解,是解决最优化问题时的一种简单但适用范围有限的策略。在解的范围下,可以采用枚举和递归策略,找出所有的解,一一比较它们,最后找到最优解,但是当解的范围特别大时,蛮力枚举或递归搜索策略效率非常低,可能在短时间内无法找到问题的解。这时,可以考虑贪心算法选取那些最可能达解的情况来考虑。“贪婪”可以理解成以逐步的局部最优,达到最终的全局最优。

特征:

  1. 最优子结构性质:即当一个问题的最优解包含其子问题的最优解时,称此问题具有最优解子结构,也称此问题满足最优性原理。
  2. 贪心选择性质:指问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来得到。(后续讲的到的动态规划和贪心算法的区别:前者是自底向上,后者是自顶向下)

基本步骤:

  1. 从问题的某个初始解出发
  2. 采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个部分解,缩小问题的范围或规模
  1. 将所有部分解综合起来,得到问题的最终解

借题理解

Case:用最少货币数找零

假设有面值 5元,2元,1元,5角,2角,1角的货币,需要找给顾客4元6角现金,但必须要求付出货币数量最少。

问题解:

首先我们要找零4元6角,我们面值最大的一张是5元,不符合要求,所以只能用2元一张,剩下2元6角,那么再取一张2元,只剩6角。虽然我们能够找3张2角解决,但是题目要求最少货币数。那只能找再找出一张面值不超过6角的货币,即5角。最后找到一张不超过1角的面值货币,即1角。因此,我们总共付出4张货币(2元两张,一张5角,一张1角)

问题总结:

在付款问题中,每一步的贪心选择中,在不超过应付金额的条件下,只能选择面值最大的货币,而不去考虑在后面看这种选择是否合理,而且它还不会改变决定,一旦选择了一张货币,就永远选定,也就是无后性

求解问题中应该考虑:

  1. 候选集合:为了构造问题的解决方案,有一个候选集合作为问题的可能解(即问题的最终解均取自候选集合) 例如:在找零问题中,各种面值货币构成的候选集合(5元,2元,1元,5角,2角,1角)
  2. 解集合:随着贪心选择的进行,解集合不断扩展,直到构成一个满足问题的完整解。例如:以付出的货币构成解集合 (只能用2元一张,剩下2元6角,那么再取一张2元,只剩6角。)
  1. 解决函数:检查解集合是否构成问题的完整解例如:在找零问题中,解决函数是已付出货币金额恰好等于应付款
  2. 选择函数(核心):即贪心策略,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。 例如:贪心策略就是在候选集合中选择面值最大的货币
  1. 可行函数:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。 例如:可行函数是每一步选择货币和已找零货币相加不超过找零总数(零4元6角)

总结

贪心算法其实在数据结构中也常见到:霍夫曼树,构造最小生成树的Prim算法和Kruskal算法。贪心算法没有固定的算法框架,核心在与贪心策略的选择,一定要注意的是选择的贪心策略要具有无后性(即某阶段的状态确定过后,不受这个状态以后的决策影响,也就是说某转态以后的过程不会影响到以前的状态) ,只与当前状态有关。因此,在使用贪心算法时,对所采用的贪心策略一定要仔细分析是否具有无后性。特别注意点:贪心算法是局部最优,最后的整体不一定最优的,和后面要说的动态规划有区别。但它通常能获得近似最优解。


跋尾

本篇内容就到这里了~ 我是Zeus👩🏻‍🚀来自一个互联网底层组装员,下一篇再见! 📖