贪心算法:从“瞎蒙”到稳赚

前言

贪心算法,顾名思义就是要贪心,古话说得好: "智者虑远,愚者虑近"。贪心需要不看长远利益而是只看眼前最大利益,所以算法的核心思想就是不考虑接下来步骤的影响,我们只考虑当前这一步是我们的"最优解"即可。通过每一步的最优解从而得到全局的"最优解"。

PS:这里的全局"最优解"不一定是所有整体方案中的最优解。因为我们的每一步是没考虑后续影响的。这是一种粗暴简单的方法,看重每一步的最优解法来认为整体的流程都是最优的方法。

经典找零钱问题

让我们再来回顾一下经典的找零钱问题

假设我们有面额为1元5元10元25元的硬币。你要找给顾客83元,用最少的硬币数量。

既然我们上面说了要只看前利益,所以我们每次找钱的时候就以结果为用最大的面额,这样就能用最少的数量去找零钱。

思路: 每一次给的硬币都是面额最大的。

  1. 找83元:拿一枚25元硬币,还剩58元。
  2. 找58元:拿一枚25元硬币,还剩33元。
  3. 找33元:拿一枚25元硬币,还剩8元。
  4. 找8元:拿一枚5元硬币,还剩3元。
  5. 找3元:拿三枚1元硬币。

最终我们得到了3个25元1个5元3个1元 ,总共7枚硬币。这在所有组合的方案中确实是最优解。

但是我们也说了贪心算法只是我们通过每一步做最优解希望最终组合的方案是最优解,他大部分情况下可以不错的解决问题,但也不是一个万能的办法。比如下面的问题

面额为 1元5元10元12元的硬币,现在要找给顾客 15元

再一次贪心算法 我们每一步组合总是选择面额最大的硬币:

  1. 找15元 :先拿一枚 12元 硬币,还剩下 3元
  2. 找3元 :只能拿三枚 1元 硬币。

现在的组合是1个12元3个1元 ,总共使用了 4枚硬币,然而就我们的认知来说实际上可以直接给3个5元 ,这样就只需要3枚硬币了。所以由此可见,贪心算法固然好用,但是有时候他也会不靠谱(所有出现了动态规划)。

做个算法题

既然我们现在了解了贪心算法到底是个啥思想,那么我们来做个算法题融会贯通下。题目出自力扣

题目

题目大意:传入一个数组nums,从0下标开始,以当前索引为i,索引对应的值为v,我们可以选择跳到i+n(n<= v)的新索引位置,然后以新的索引位置来决定跳到的下一个索引。判断这个数组是否能跳完,能跳完返回true,否则false

分析与实现

  1. 分析题目第一步我们要确定我们的结果是能否跳出我们的数组,那么我们实际上就是算的当前的i+v是否能大于等于nums长度-1,可得当前可最大跳到的索引maxIndex=nums[i]+i
  2. 我们只需要判断当maxIndex=nums[i]+i>=nums.length-1时返回true即可。
  3. 因为我们只要保证能跳出这个数组,并且没有求刚好跳出的这种最优解,所以我们可以利用贪心算法的思想,每一次我们只管当前的最大可跳跃到的位置nums[i]+i。先不去考虑可能 接下来会造成跳到0造成无法结束数组,但是实际上如果跳一个小于nums[i]的值再通过下一个索引去跳就可以绕过0去避免提前结束的情况。
  4. 对于我们3说的提前结束的情况,我们可以去判断当前我们的索引是否已经超过了最大可以跳到的索引nums[i]+i即可解决。当我们从当前跳到的最大值也无法超过我们索引值的时候,就代表无法通过新的索引去往下跳了,也就是出现示例2的那种情况。

代码实现

kotlin 复制代码
fun canJump(nums: IntArray): Boolean {
    //当前可跳到的最大索引
    var maxIndex = 0
    for ((index, item) in nums.withIndex()) {
        //判断当前之前跳到的最大位置是否能到达新的遍历点,如果无法到达证明跳不到这里,直接返回false
        if (maxIndex < index) {
            return false
        }
        //每个新的位置都以当前新位置可到达的最大点作为下一个跳达点去和之前的最大可跳达点比较
        //如果还没之前跳的远那就以之前的跳达点为主
        maxIndex = max(index + item, maxIndex)
    }
    //当可以遍历完就证明必然可以达到终点
    return true
}

55. 跳跃游戏 - 力扣(LeetCode)

看起来我们的结果并没有问题,证明我们使用贪心算法去解决也是正确的。

贪心算法是一种很简单粗暴的解题思路,也是用的非常多的一种算法,例如最小生成树、最短路径,找零钱。又比如生活中我们赶飞机或火车要坐多个交通换乘时一般都会在每一个交通选择上先做最快的选择,而不是卡死这个刚好到达的时间,当你面对一个新问题他需要多个步骤时,可以先尝试用贪心算法来思考。如果能证明它的贪心选择是正确的,那么这种方法通常是最简单高效的。😎

相关推荐
盖雅工场2 分钟前
连锁零售排班难?自动排班系统来解决
大数据·人工智能·物联网·算法·零售
Greedy Alg5 分钟前
LeetCode 438. 找到字符串中所有的字母异位词
算法·leetcode·职场和发展
Q741_1475 分钟前
C++ 力扣 76.最小覆盖子串 题解 优选算法 滑动窗口 每日一题
c++·算法·leetcode·双指针·滑动窗口
lifallen5 小时前
Hadoop MapReduce 任务/输入数据 分片 InputSplit 解析
大数据·数据结构·hadoop·分布式·算法
熙xi.6 小时前
数据结构 -- 哈希表和内核链表
数据结构·算法·散列表
Ghost-Face6 小时前
并查集提高——种类并查集(反集)
算法
董董灿是个攻城狮7 小时前
5分钟搞懂大模型微调的原始能力退化问题
算法
alexhilton7 小时前
Compose Unstyled:Compose UI中失传的设计系统层
android·kotlin·android jetpack
kerli10 小时前
kotlin协程系列:callbackFlow
android·kotlin