Medium
题目描述
给你一个整数数组 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 <= 121 <= coins[i] <= 2^31 - 10 <= amount <= 10^4
解题思路
这是一道经典的动态规划问题,也可以用BFS求解。
动态规划思路(推荐):
定义 dp[i] 表示凑成金额 i 所需的最少硬币数。状态转移方程为:
dp[i] = min(dp[i], dp[i - coin] + 1),其中 coin 是硬币面额且 coin <= i。
初始状态:dp[0] = 0(凑成0元需要0个硬币),其余位置初始化为一个较大值表示不可达。
BFS思路: 将问题看作图的最短路径问题。从金额0开始,每次尝试加上一个硬币面额,直到达到目标金额。BFS能保证找到的第一个解就是最优解。
贪心思路(不推荐):
优先使用大面额硬币,但这种方法在某些情况下无法得到最优解,比如 coins = [1,3,4], amount = 6,贪心得到 4+1+1=3个硬币,但最优解是 3+3=2个硬币。
动态规划方法时间复杂度更好,代码更简洁,是首选解法。
代码实现
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (i >= coin) {
dp[i] = min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
};
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [amount + 1] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for coin in coins:
if i >= coin:
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] <= amount else -1
public class Solution {
public int CoinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Array.Fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
foreach (int coin in coins) {
if (i >= coin) {
dp[i] = Math.Min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
var coinChange = function(coins, amount) {
const dp = new Array(amount + 1).fill(amount + 1);
dp[0] = 0;
for (let i = 1; i <= amount; i++) {
for (let coin of coins) {
if (i >= coin) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
};
复杂度分析
| 复杂度类型 | 动态规划解法 |
|---|---|
| 时间复杂度 | O(amount × coins.length) |
| 空间复杂度 | O(amount) |
相关题目
. Minimum Cost For Tickets (Medium)
. Length of the Longest Subsequence That Sums to Target (Medium)
. Inverse Coin Change (Medium)