一、题目

给你一个整数数组 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

示例 4:

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

示例 5:

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



提示:

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

二、思路
  • 完全背包:dp[i][j]:代表选了前i个物品,花费为j时的价值
  • 由于每个物品可以选无数次,假设某个物品花费为v,价值为w,并且在j花费下最多选m次,这
  • dp[i][j] = max(dp[i - 1][j], max(dp[i - 1][j - v] + w, dp[i - 1][j-2v] + 2w,….,…,dp[i - 1][j-mv] + mw))
  • dp[i][j + v] = max(dp[i - 1][j + v], max(dp[i - 1][j] + w, dp[i - 1][j - v] +2 w, dp[i - 1][j-2v] + 3w,….,…,dp[i - 1][j-mv] + (m+1)w))
  • 所以上述式子可以简化为dp[i][j + v] = max(dp[i - 1][j + v], dp[i][j] + w)
  • 综上所述:完全背包的状态转移为: dp[i][j] = max(dp[i - 1][j], dp[i][j - v] + w)
三、代码

class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<int> dp(amount + 1, 1e5);
dp[0] = 0;
for (int i = 0; i < n; i++) {
int v = coins[i];
for (int j =v; j <= amount; j++) {
dp[j] = min(dp[j], dp[j - v] + 1);
}
}
return dp[amount] == 1e5 ? -1 : dp[amount];
}
};