返回

分解零钱花样多:LeetCode 518 零钱兑换 II 的组合计数

前端

在日常生活中,我们经常会遇到找零钱的情况。当你用一张大面额的钞票购买小额商品时,收银员通常会找给你各种面额的硬币。那么,对于给定的面额和总金额,有多少种不同的找零方式呢?

这个问题正是 LeetCode 518 零钱兑换 II 中提出的问题。该问题要求我们编写一个函数,给定不同面额的硬币和一个总金额,计算有多少种方法可以凑成总金额。

为了解决这个问题,我们可以采用动态规划的方法。具体来说,我们可以定义一个二维数组 dp,其中 dp[i][j] 表示使用前 i 种硬币凑成金额 j 的方法数。

def change(amount, coins):
  """
  计算使用给定的硬币凑成总金额的方法数。

  Args:
    amount: 总金额。
    coins: 硬币面额列表。

  Returns:
    凑成总金额的方法数。
  """

  # 初始化 dp 数组。
  dp = [[0] * (amount + 1) for _ in range(len(coins) + 1)]

  # 初始化第一行和第一列。
  dp[0][0] = 1
  for j in range(1, amount + 1):
    dp[0][j] = 0

  # 填充 dp 数组。
  for i in range(1, len(coins) + 1):
    for j in range(1, amount + 1):
      dp[i][j] = dp[i - 1][j]
      if j >= coins[i - 1]:
        dp[i][j] += dp[i][j - coins[i - 1]]

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

使用动态规划的方法,我们可以有效地计算出凑成总金额的方法数。该算法的时间复杂度为 O(amount * len(coins)),其中 amount 是总金额,len(coins) 是硬币面额的个数。

为了加深理解,我们来看一个具体的例子。假设我们有面额为 1、2、5 的硬币,总金额为 10。那么,凑成 10 元的方法数为:

10 = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
10 = 1 + 1 + 1 + 1 + 1 + 1 + 2 + 2
10 = 1 + 1 + 1 + 1 + 1 + 5
10 = 1 + 1 + 1 + 2 + 5
10 = 1 + 1 + 2 + 2 + 2 + 2
10 = 1 + 2 + 2 + 5
10 = 2 + 2 + 2 + 2 + 2
10 = 5 + 5

因此,凑成 10 元的方法数为 8。

通过 LeetCode 518 零钱兑换 II 这道题,我们不仅学习了一种解决问题的动态规划方法,还锻炼了我们的逻辑思维能力。在实际生活中,我们也会经常遇到类似的问题,例如如何分配资源以实现最大收益。因此,这道题不仅在算法方面有意义,在现实生活中也有很强的实用价值。