322 零钱兑换

本文最后更新于:2022年4月9日 中午

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1

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

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

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

示例 5:

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

提示:

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

Solution

思路参考:动态规划解题套路框架liuyubobobo

  • dp 数组的定义:当目标金额为 i 时,至少需要 dp[i] 枚硬币凑出。
  • dp 数组的迭代解法所需要的步骤最少,时间更短

image-20201020162156611

1
2
3
4
5
6
7
8
9
10
11
# @lc code=start
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [amount+1]*(amount+1)
dp[0] = 0
for i in range(len(dp)):
for coin in coins:
if (i-coin)<0: continue
dp[i] = min(dp[i], 1+dp[i-coin])
return dp[amount] if dp[amount] != amount+1 else -1
# @lc code=end

cpp

  • 记忆优化搜索,整型溢出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
private:
vector<int> memo;

int go(const vector<int>& coins, int amount){
if(amount==0){
return 0;
}

if(memo[amount] != -1)
return memo[amount];

int res = INT_MAX;
for(int i=0; i<coins.size(); ++i){
if(amount >= coins[i])
res = min(res, 1+go(coins, amount-coins[i]));
}
memo[amount]=res;
return res;
}

public:
int coinChange(vector<int>& coins, int amount) {
if(coins.size()==0 || amount<=0)
return 0;
memo = vector<int>(amount+1, -1);
int res = go(coins, amount);
return res;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if(coins.size()==0 || amount<=0)
return 0;

vector<int> dp(amount+1, amount+1);
dp[0] = 0;
for(int coin : coins)
for(int j=coin; j<=amount; ++j)
dp[j] = min(dp[j], dp[j-coin] +1);

if(dp[amount]==amount+1) return -1;
return dp[amount];
}
};

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!