数据结构与算法之贪心算法

131 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情

作者: 千石
支持:点赞、收藏、评论
欢迎各位在评论区交流

前言

本文内容来自我平时学习的一些积累,如有错误,还请指正

在题目实战部分,我将代码实现和代码解释设置在了解题思路的下方,方便各位作为参考刷题

一些话

本文内容来自我平时学习的一些积累,如有错误,还请指正

在题目实战部分,我将代码实现和代码解释设置在了解题思路的下方,方便各位作为参考刷题

题目练习步骤:

  1. 给自己10分钟,读题并思考解题思路
  2. 有了思路以后开始写代码,如果在上一步骤中没有思路则停止思考并且看该题题解
  3. 在看懂题解(暂时没看懂也没关系)的思路后,背诵默写题解,直至能熟练写出来
  4. 隔一段时间,再次尝试写这道题目

前置知识

贪心算法定义

顾名思义就是说,一种在每一步选择中都采取在当下状态下最好,最优的选择希望导致结果是全局最好或者最优的。

最后是希望结局导致全局最好或者最优,采取的办法就是在当下选择最好或者最优的,但当下最好/最优的并不一定是全局最好最优的。

贪心算法与回溯、动态规划的不同点

算法区别
贪心当下做局部最优判断
回溯能够回退
动态规划最优判断 + 回退

贪心法主要解决的是一些最优化问题最小生成树、求哈夫曼编码等),对于工程或者生活中的问题,贪心法一般来说不能得出我们想要的答案

实战

题目:322. 零钱兑换 - 力扣(LeetCode)

image.png

思路:

  1. 定义一个数组 dp,其中 dp[i] 表示凑成总金额为 i 所需的最少的硬币个数。
  2. 初始化 dp[0] = 0,因为凑成总金额为 0 时不需要任何硬币。
  3. 遍历每一个硬币 coin,如果 coin 的面值小于等于总金额 i,则更新 dp[i] 的值,使其成为 dp[i-coin]+1 和当前的 dp[i] 中的较小值。这里,dp[i-coin]+1 表示加上一枚硬币 coin 后凑成总金额为 i 的最小硬币数。
  4. 最后,如果 dp[amount] 的值不是无穷大,则返回 dp[amount],否则返回 -1

代码实现:

def coinChange(coins, amount):
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0
    for i in range(1, amount + 1):
        for coin in coins:
            if coin <= i:
                dp[i] = min(dp[i], dp[i - coin] + 1)
    return dp[amount] if dp[amount] != float('inf') else -1

时间复杂度分析:

设数组 `coins` 的长度为 `n`,则时间复杂度为 $O(n \times amount)$。
image.png