美文网首页
零钱找零

零钱找零

作者: Wu杰语 | 来源:发表于2021-12-27 17:50 被阅读0次

零钱找零问题,题目是这样的

You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.

Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

例如:

Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1

解决这样的问题,可以使用到的方法有贪心算法、暴力递归或lookback、动态规划算法。

贪心算法

如果对于某个总数一定有解,那么套用贪心算法,能很容易得到一个解决方法

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        count = 0
        rest = amount
        i = len(coins) - 1
        coins.sort()
        while i >= 0:
            curCount = rest//coins[i]
            rest -= coins[i] * curCount
            count += curCount
            if rest == 0:
                return count
            i -= 1
        return -1

过程:

  • 先用最大的硬币来找零,用2个5元,剩下1元
  • 使用2元硬币找零,发现只能用0个
  • 最后使用1元硬币,可以用1个

总共最优使用3个硬币。这是贪心算法,最容易想到和使用的方法。这种情况算法复杂度是O(n)

lookback回溯

但是,可能有个问题,如果硬币面额比较多,可能用贪心算法,刚好得不到解,但是实际上是有解的。这种情况需要怎么办,需要使用回溯递归遍历。

    def coinChange(self, coins, amount):
        if not amount: return 0
        return self.dfs(coins, amount, amount)
        
    def dfs(self, coins, amount, rem):
        if rem < 0: return -1
        if rem == 0: return 0
        tempMin = amount + 1
        for coin in coins:
            res = self.dfs(coins, amount, rem - coin)
            if res and res < tempMin:
                tempMin = res
        return tempMin

这是一种回溯算法,使用了深度搜索方法,负责度也是指数级别的O(n^len(coins)),负责度比较高。

怎么优化呢,使用缓存,即备忘录优化,把中间结果缓存下来

def coinChange(self, coins, amount):
        if not amount: return 0
        return self.help(coins, amount, amount, [0]*(amount + 1))
        
    def help(self, coins, amount, rem, count):
        if rem < 0: return -1
        if rem == 0: return 0
        if count[rem-1] != 0: return count[rem-1]
        tempMin = amount + 1
        for coin in coins:
            res = self.help(coins, amount, rem - coin, count)
            if res and res < tempMin:
                tempMin = res
        count[rem-1] = -1 if tempMin == amount + 1 else tempMin
        return count[rem-1]

这种情况优化下来,复杂度也是O(n)的

动态规划

有没有更好的算法呢,那就是动态规划,动态规划满足:

  • 重叠子问题:在穷举的过程中(比如通过递归),存在重复计算的现象;
  • 无后效性:子问题之间的依赖是单向性的,某阶段状态一旦确定,就不受后续决策的影响;
  • 最优子结构:子问题之间必须相互独立,或者说后续的计算可以通过前面的状态推导出来。

在解决过程中最重要的是写出动态转移方程:
coinchange的动态转移方程是:
dp[i] = min(dp[i], dp[i-coin] + 1)
指导状态转移方程,就很容易得到代码了:

    def coinChange_dp(self, coins, amount):
        dp = [amount + 1] * (amount + 1)
        dp[0] = 0
        for i in range(1, (amount + 1)):
            for coin in coins:
                if i >= coin:
                    dp[i] = min(dp[i], dp[i-coin] + 1)
        return dp[amount] if dp[amount] <= amount else -1

这个算法复杂度就是O(n)了

小结

coinChange虽然比较简单,但是要想清楚其中问题的关键,还是要把所有可能的算法都思考一遍。特别是只用贪心算法,就会考虑不到有可能得不到解的情况;只有动态规划,可能就不知道怎么得来动态规划的。

相关文章

  • 背包问题详解

    目录 问题引入 在介绍背包问题之前,我们先来看一个小问题:找零钱问题。 找零钱问题 背包问题的一个浅显版本是找零钱...

  • 【找零钱】

    用python写一个找零钱的算法。 零钱共有50块,20块,10块,5块,和1块,共5种。。例:69 = 50 +...

  • 找零钱

    10人以上 如:男生1元,女生0.5元 围城一圈,中间站一人 主持人:“大家都来找零钱” 大家问:“找多少?” 主...

  • 找零钱

    给定一个数组,数组中为不同的数代表不同钱的面值,同时给定一个需要兑换零钱的钱数,任意使用不同面值不同数量的钱来兑换...

  • 算法思想之动态规划(三)——找零钱问题

    前言 今天我们继续讨论经典的动态规划问题之找零钱问题。 找零钱问题 问题描述 假设你是一名超市收银员,现有种不同面...

  • 找零钱问题

    问题 这个题目要求编写一段程序实现统一银座超市的找零方案。只需输入要补给顾客的 金额,然后通过程序就可以计算出该金...

  • 零钱找零

    零钱找零问题,题目是这样的 例如: 解决这样的问题,可以使用到的方法有贪心算法、暴力递归或lookback、动态规...

  • 贪心--找零钱

    目录[https://www.jianshu.com/p/85e18c21317a] 题号[https://lee...

  • 过年乐

    春日渐暖天湛蓝,街区巷口人如烟, 儿童摊前糖瓜少,翻遍衣兜找零钱。

  • 找零的技巧(日更第107天)

    曾经帮亲戚家卖鞭炮的时候,说起了找零的话题,说要是找钱,先找零钱,在找整的,也许顾客没有等到你给他整钱,他就...

网友评论

      本文标题:零钱找零

      本文链接:https://www.haomeiwen.com/subject/pabyqrtx.html