leetcode 322. 零钱兑换
分析: 题意要求计算从给定的不同面额的硬币数组中能凑成总金额所需要的最少硬币个数,如果没有任何一种硬币能组成总金额,则返回-1,并且硬币的数量是无限的,因此本题可以看成是一个完全背包问题。
- 背包容量:总金额
amount
- 物品:硬币
coins
解题步骤(参考代码随想录中的动规五部曲):
- 确定递推数组
dp
的含义:将dp[i]
定义为组成金额为i
最少需要的硬币数量; - 确定递推公式:
dp[i]
可以由dp[i - coins[j]] + 1
来得到,既凑成i - coins[j]
的最少硬币数量为dp[i - coins[j]]
,那么再加上一个coins[j]
就能得到凑成金额为i
的硬币数量dp[i]
,由于题意是求最少硬币数量,所以递推公式为dp[i] = min(dp[i], dp[i - coins[j]] + 1)
; dp
数组进行初始化:因为要取最小值,所以初始化不能是一个很小的值,在这里可以将dp
数组全部初始化为INT_MAX
(int型的最大值),其中dp[0] = 0;- 确定背包和物品的遍历顺序:在这里先遍历背包和先遍历物品都一样,但是由于在这里我们将
dp
数组全部初始化为INT_MAX
,因此在进行递归计算之前需要先判断一下i - coins[j]是否为INT_MAX,如果不是再进行计算,不然dp[i - coins[j]] + 1会溢出报错;
完整代码:
这是先遍历的物品再遍历的背包
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0;
for (int i = 0; i < coins.size(); ++i) {
for (int j = coins[i]; j <= amount; ++j) {
if (dp[j - coins[i]] != INT_MAX) {
dp[j] = min(dp[j], dp[j - coins[i]] + 1);
}
}
}
return dp[amount] == INT_MAX ? -1 : dp[amount];
}