📜  查找总和为给定金额的最小纸币和价值数量(1)

📅  最后修改于: 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
总结

本题是一个比较典型的动态规划问题,难度适中。需要注意初始化数组元素的值,以及最终返回值的处理。