📅  最后修改于: 2023-12-03 15:26:37.824000             🧑  作者: Mango
这个问题可以被视为一个变种的背包问题。给定一组纸币面值,我们需要从中选出若干张纸币,使它们的总和等于给定金额,且所选的纸币数量最少。
设给定的纸币面值为 coins
,大小为 n
,要求组成的总金额为 amount
。
我们可以使用动态规划来求解问题。我们定义一个二维数组 dp
,其中 dp[i][j]
表示在只使用前 i
种纸币,凑出金额 j
的最小纸币数量。
最终的答案即为 dp[n][amount]
。
对于 dp[i][j]
,有两种情况:
如果我们不选第 i
种纸币(下标从 0 开始),那么它的值就是 dp[i-1][j]
。
如果我们选第 i
种纸币,那么它的值就是 dp[i][j-coins[i-1]] + 1
,其中 dp[i][j-coins[i-1]]
表示使用当前纸币面值减去当前金额的最小纸币数量,再加上当前选中的纸币一张。
要使数量最小,我们只需要在两种情况中选择较小值即可。
具体实现上,我们可以先把数组所有元素初始化为一个较大的值,如 amount + 1
。
dp = [[amount + 1] * (amount + 1) for _ in range(n + 1)]
然后将 dp[i][0]
都赋值为 0,因为凑出金额 0 的最小纸币数量为 0。
对于其他元素,按照上面的动态转移方程计算即可。
最后,如果 dp[n][amount]
仍然等于 amount + 1
,说明无法凑出指定金额,返回 -1,否则返回 dp[n][amount]
。
以下是 Python 代码实现:
def coin_change(coins, amount):
n = len(coins)
dp = [[amount + 1] * (amount + 1) for _ in range(n + 1)]
for i in range(n + 1):
dp[i][0] = 0
for i in range(1, n + 1):
for j in range(1, amount + 1):
if j < coins[i-1]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = min(dp[i-1][j], dp[i][j-coins[i-1]] + 1)
return dp[n][amount] if dp[n][amount] <= amount else -1
本题是一个比较典型的动态规划问题,难度适中。需要注意初始化数组元素的值,以及最终返回值的处理。