携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
大家好呀,我是帅蛋。
今天我们来学习贪心算法,它和我之前带大家玩儿的【递归算法】、【分治算法】类似,带着算法的名儿,但实际上是一种解决问题的思想策略。
在正式开始之前,我想先说几句题外话:
我知道贪心算法对很多同学来说有点难,这个难不是难在对概念的理解上,而是一看就会,一做题就废,接着半途而废。
这个我想说很正常,因为贪心算法是一种算法【思想】,但凡是这种的,就没什么套路可讲,不像我们在上个专题学二叉树的时候,解题就是递归 + 迭代,可以由上到下、由下到上、由左到右的整,套路明显。
更不用说,后面碰到动态规划的时候,更容易贪心算法和动态规划用哪个傻傻分不清楚。
碰到这些问题怎么办?就是干,唯做题 + 总结。
写这篇文章应该篇幅不会很多,我会带你了解一下什么是贪心算法,重头戏是会在后面的实战题板块,我来带你做题和做总结,所以跟着搞就完事了。
R u ready?gogogo!
贪心算法
学习贪心算法,首先我们得从它的概念学起。
贪心算法(greedy algorithm) 是指从问题初始转状态出发,通过在每一步选择中都采取最好或者最优(最有利)的选择,从而得到结果的最优值(或较优值)。
通过概念我们能知道贪心算法的 2 个关键点:
- 贪心算法在对问题进行求解时,总是做出当前看来最好的选择。
- 通过贪心算法所得到的结果不一定是最优的结果,但肯定都是相对接近最优解的结果。
看起来这 2 点可能不好理解,我用两个例子你就懂了。
例 1:我们现在有 20、10、5、1 这 4 种数额的钱币,如果想要凑齐 36 元,那我最少需要几张钱币?
如果根据贪心算法的话,我们上来肯定是看需要几张 20 的,这道题需要 1 张,那还剩 36 - 20 = 16。
看完 20 的我们再来看 10 元的,需要 1 张 10 元,现在还剩 16 - 10 = 6。
下面继续是看 5 和 1,分别就需要 1 张。
最后我们得到的答案是,如果想要凑齐 36 元我们最少需要 4 张纸币。
这个例子,每次都是用最大的纸币去匹配,剩下的余额再用较小点的面额去匹配,这个就是第 1 点我们说的,在对问题进行求解时,每次都是做出当前看来最好的选择。
例 2:我们还是以撒币为例,现在我们有 10、9、1 这 3 种金额的钱币,如果想要凑齐 18 元,咱最少需要几张钱币?
在这个例子,如果我们还是用上面的贪心策略,那就完蛋了。
我上来就看需要几张 10 元,那这道题需要 1 张,剩余金额是 8 元,那我无法用 9 的纸币,只能用 8 张 1 元的纸币,那这最后的结果是用了 9 张纸币。
而通过小学知识,我们肉眼就能看出用 2 张 9 元的纸币就 ok 了。
通过这个例子就是说明了第 2 点:通过贪心算法所得到的结果不一定是最优的结过。
看到这是不是懵了?懵了就对了。
你现在就先记住一点:贪心算法只是在部分情况下有用。至于什么是部分情况,这个就得靠多做题了~
诶诶诶,你先别动手,那你看嘛,就比如上面的 2 个例子,你要看看数之间的规律,例 1 的中的币互相成倍数,例 2 中就没啥规律。
这个就得是靠多做题多总结好伐~
什么时候用贪心?
说实话,这就是贪心算法对我们来说”难“的地方,即没有模式化的东西直接了当的告诉我们”这样就是用贪心“。
如果硬要说的话,绝大多数用在像上一节中举的例子那种【组合优化】问题,求解的过程涉及到多步判断。
碰到这样的题,你的想法可以往贪心算法上靠一靠,但也只是”可以“而已。
因为你看到类似这种问题,你想到贪心算法,首先就要自己先搞出个贪心策略,之后你要验证你所用的贪心策略产生的结果是不是最优的,如果不是最优的,那可能就要用到我们下一个专题要学的【动态规划】。
大家估计会问如何验证,直接就举几个靠谱的例子验证就好了。
当然这里我说的是”靠谱“,就是一些特例,不然你随便整了几个例子,发现都对,这个时候你就觉得你做的就是对的,恰恰也可能你举的这几个例子正好巧了。
这里我还想多说几句:
其实按照正常来说呢,像这种验证贪心算法的正确性,最靠谱的就是通过数学推导来弄,一般像什么数学归纳法、反正法这种方法。
但是怎么说呢,数学推导虽然很对,结果也很正确,但是对于我们来说完全没有必要,且不说很多人根本不会推导,就算会,对我们来说意义也不大,毕竟目的性不一样,这样搞就走远了。
从我们刷题的角度来看,我们完全就可以靠举一些特例就能验证绝大多数问题。
当然像这种举特例的能力,你要问我怎么举,我只能告诉你:多做题就有了。
贪心法题解步骤
贪心算法的解题步骤,其实和分治算法很像的。
我在之前讲分治算法的时候讲过分治算法的 3 个步骤:
划分(Divide) :将原问题划分为规模较小的子问题,子问题相互独立,与原问题形式相同。
求解(Conquer) :递归的求解划分之后的子问题。
合并(Combine) :这一步非必须。有些问题涉及合并子问题的解,将子问题的解合并成原问题的解。有的问题则不需要,只是求出子问题的解即可。
贪心算法的步骤也类似,如果你确定是贪心算法可解,也是 3 个步骤:
(1) 将问题分解为多个子问题。
(2) 选择合适的贪心策略,得到每一个子问题的局部最优解。
(3) 将子问题的局部最优解合并成原问题的最优解。
是不是这么看觉得还挺简单的?嘿嘿嘿嘿,等做题的时候你就知道有时候看到的并不就是真实的感受~
贪心算法的内容到这就说的差不多了,单纯理论上的东西确实不多,看完了也只是让你有个印象。
关于理论上的东西你只要了解就行,你想学好贪心别无他法。就是要多做题多练习,见的多了就有感觉了。
其实一连套的动作就是:诶,这道题看着能用贪心,试试,得出个结果,找几个特例验一验,是最优解万事大吉,不是最优解,就再想想是不是动态规划啥的可以解。
最后再说一句,贪心算法不用慌,退一万步讲,贪心就算学的不好,问题也不大,面试的时候贪心考的一般比较少。
毕竟生活啊,总归是要全局考虑,哪能只盯着眼前~
我是帅蛋,我们下次见!