LeetCode 题解工作台

零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种硬币的数量是无限的。 示例 1: 输入: coins = [1, 2, 5] , am…

category

3

题型

code_blocks

7

代码语言

hub

3

相关题

当前训练重点

中等 · 状态·转移·动态规划

bolt

答案摘要

我们定义 表示使用前 种硬币,凑出金额 的最少硬币数。初始时 $f[0][0] = 0$,其余位置的值均为正无穷。 我们可以枚举使用的最后一枚硬币的数量 ,那么有:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1

你可以认为每种硬币的数量是无限的。

 

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

 

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 231 - 1
  • 0 <= amount <= 104
lightbulb

解题思路

方法一:动态规划(完全背包)

我们定义 f[i][j]f[i][j] 表示使用前 ii 种硬币,凑出金额 jj 的最少硬币数。初始时 f[0][0]=0f[0][0] = 0,其余位置的值均为正无穷。

我们可以枚举使用的最后一枚硬币的数量 kk,那么有:

f[i][j]=min(f[i1][j],f[i1][jx]+1,,f[i1][jk×x]+k)f[i][j] = \min(f[i - 1][j], f[i - 1][j - x] + 1, \cdots, f[i - 1][j - k \times x] + k)

其中 xx 表示第 ii 种硬币的面值。

不妨令 j=jxj = j - x,那么有:

f[i][jx]=min(f[i1][jx],f[i1][j2×x]+1,,f[i1][jk×x]+k1)f[i][j - x] = \min(f[i - 1][j - x], f[i - 1][j - 2 \times x] + 1, \cdots, f[i - 1][j - k \times x] + k - 1)

将二式代入一式,我们可以得到以下状态转移方程:

f[i][j]=min(f[i1][j],f[i][jx]+1)f[i][j] = \min(f[i - 1][j], f[i][j - x] + 1)

最后答案即为 f[m][n]f[m][n]

时间复杂度 O(m×n)O(m \times n),空间复杂度 O(m×n)O(m \times n)。其中 mmnn 分别为硬币的种类数和总金额。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        m, n = len(coins), amount
        f = [[inf] * (n + 1) for _ in range(m + 1)]
        f[0][0] = 0
        for i, x in enumerate(coins, 1):
            for j in range(n + 1):
                f[i][j] = f[i - 1][j]
                if j >= x:
                    f[i][j] = min(f[i][j], f[i][j - x] + 1)
        return -1 if f[m][n] >= inf else f[m][n]

我们注意到 f[i][j]f[i][j] 只与 f[i1][j]f[i - 1][j]f[i][jx]f[i][j - x] 有关,因此我们可以将二维数组优化为一维数组,空间复杂度降为 O(n)O(n)

相似题目:

1
2
3
4
5
6
7
8
9
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        n = amount
        f = [0] + [inf] * n
        for x in coins:
            for j in range(x, n + 1):
                f[j] = min(f[j], f[j - x] + 1)
        return -1 if f[n] >= inf else f[n]
speed

复杂度分析

指标
时间complexity varies: DP approach is O(amount * n) where n is number of coins; BFS may also approach similar bounds. Space complexity is O(amount) for DP array or BFS visited set.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Checks if candidate recognizes state transition DP pattern for minimal coin computation.

  • question_mark

    Looks for proper handling of edge cases like unreachable amounts or zero amount.

  • question_mark

    Observes whether BFS alternative is considered for level-based minimal coin counting.

warning

常见陷阱

外企场景
  • error

    Failing to initialize DP array correctly leading to invalid minimum computations.

  • error

    Ignoring unreachable sums, resulting in incorrect positive coin counts instead of -1.

  • error

    Overcounting coins by revisiting states without pruning already processed amounts.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Compute minimum coins when coins have limited quantity instead of infinite supply.

  • arrow_right_alt

    Return all possible combinations of coins that sum to the target amount.

  • arrow_right_alt

    Determine the number of ways to make up the amount rather than the minimal coins.

help

常见问题

外企场景

零钱兑换题解:状态·转移·动态规划 | LeetCode #322 中等