返回

动态规划巧妙破解零钱兑换难题

后端

理解零钱兑换问题

零钱兑换问题是这样一个问题:给定不同面额的硬币和一个总金额,计算有多少种方法可以将总金额用这些硬币凑齐。例如,给定硬币面额为 [1, 2, 5] 和总金额为 5,那么有 4 种方法可以凑齐 5 元:

  • 1 个 5 元硬币
  • 2 个 2 元硬币和 1 个 1 元硬币
  • 1 个 2 元硬币和 3 个 1 元硬币
  • 5 个 1 元硬币

使用动态规划解决零钱兑换问题

动态规划是一种解决优化问题的有力工具,它将问题分解成更小的子问题,然后逐步解决这些子问题,最终得到整体问题的解决方案。对于零钱兑换问题,我们可以将问题分解成如下子问题:

  • 给定面额为 coins[i] 的硬币和总金额 amount,有多少种方法可以凑齐 amount

我们可以通过如下递推关系来解决该子问题:

  • amount == 0,则只有一种方法可以凑齐,即不使用任何硬币。
  • amount < 0,则没有方法可以凑齐。
  • amount > 0,则有两种情况:
    • 不使用面额为 coins[i] 的硬币,则有 dp[i-1][amount] 种方法可以凑齐。
    • 使用面额为 coins[i] 的硬币,则有 dp[i][amount - coins[i]] 种方法可以凑齐。

代码实现

def change(amount, coins):
    """
    计算有多少种方法可以将总金额用硬币凑齐。

    参数:
        amount: 总金额
        coins: 硬币面额列表

    返回:
        有多少种方法可以将总金额用硬币凑齐
    """

    # 初始化动态规划表
    dp = [[0] * (amount + 1) for _ in range(len(coins) + 1)]

    # 初始化第一行和第一列
    for i in range(len(coins) + 1):
        dp[i][0] = 1

    # 填充动态规划表
    for i in range(1, len(coins) + 1):
        for j in range(1, amount + 1):
            if coins[i - 1] <= j:
                dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]]
            else:
                dp[i][j] = dp[i - 1][j]

    # 返回结果
    return dp[len(coins)][amount]


# 示例

coins = [1, 2, 5]
amount = 5

result = change(amount, coins)

print(f"总金额为 {amount},硬币面额为 {coins},有多少种方法可以将总金额用硬币凑齐?")
print(f"答案:{result}")

结语

在本文中,我们介绍了如何使用动态规划来解决零钱兑换问题。我们从问题的定义开始,然后逐步推导解决方案,最后通过示例和代码实现来加深理解。希望读者能够从中获得启发,并将其应用于实际场景中。

需要注意的是,动态规划并不是解决所有问题的万能方法。它只适用于那些具有特定结构和性质的问题。在使用动态规划之前,需要仔细分析问题,以确定它是否适合使用动态规划来解决。