Python实现数据结构与算法——零钱兑换

题目描述:

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例1:
输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1
示例2:
输入: coins = [2], amount = 3
输出: -1
说明:

你可以认为每种硬币的数量是无限的。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

这道题可以采用动态规划的方法,主要任务就是找到状态方程。根据题意,自底向上构建状态方程。

  1. 设在给定coins=[a,b,c],a、b、c为不同面值的硬币的情况下,达到金额amount需要的最少金币个数由函数f(coins,amount)确定。
  2. 组成amount的最后一枚硬币是a、b、c中的一枚,则可以认为函数f(coins,amount)可以等价为:
    f(coins,amount) = f(coins,amount-a/b/c)+1,取最小值
  3. 基于此思路继续分析,对于任意金额i的最小金币数,一定是由(i-a/b/c)金额最小钱币数+1所得。
  4. 创建长度为amount+1的数组result记录从0-amount每一个金额需要的最小金币数,则状态方程为:
    result[i] = min(result[i-j]+1, result[i])
    这里i为总金额,j为硬币面值
    具体代码如下:
class Solution:
    def coinChange(self, coins, amount) -> int:
        num_coins = [amount+1 for i in range(amount+1)]
        num_coins[0] = 0
        if amount == 0:
            return 0
        for i in range(amount+1):
            for j in coins:
                if i >= j:
                    num_coins[i] = min(num_coins[i-j]+1,num_coins[i])
        return num_coins[amount] if not num_coins[amount] > amount else -1

测试结果:
Python实现数据结构与算法——零钱兑换_第1张图片

总结:

这道题属于典型的可以使用动态规划解答的题。看一道题能不能使用动态规划方法解答,可以看看它是否是最值问题,能不能用递归解决,能不能剪枝,如果自顶向下满足这些条件,就可以尝试自底向下的动态规划解答。核心是要分析出动态方程。据说这道题用DFS解答似乎会更快。

你可能感兴趣的:(数据结构与算法)