问题描述
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
链接:https://leetcode-cn.com/problems/coin-change/
思路
使用动态规划解题。首先创建一个一维数组dp,dp[i]表示amount=i时的最少硬币数。通过dp[i]与dp[j]之间的关系递推出dp[i],其中 j<i。
递推公式
对于amount=i来说,其中找零面值可能是coins中的任何一种面值。我们假设找零面值中有一张面值为c的钱,那么我们很容易就会看出dp[i] = dp[i-c] + 1。
结合题目条件我们可以得出:
当然,想要满足以上递推公式需要一些限制条件:
i >= c
dp[i-c]
必须有解
代码实现
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
if coins == [0]: # 特殊情况处理,该种情况下i-c=i,而i还未计算出来,初始时dp[i]=0,此时结果将会是1,但是是错误结果。
return -1
dp = [0] * (amount + 1)
for i in range(1,amount + 1):
min = amount # min为dp[i-c]的最小值,初始化为amount
for c in coins: # 寻找最小的dp[i-c]
min = dp[i-c] if i>=c and dp[i-c]!=-1 and dp[i-c]<min else min
dp[i] = min+1 if min!=amount else -1 # min=amount说明没有最小dp[i-c],即为无解
return dp[-1]