【Leetcode】完全背包问题-322. 零钱兑换
题目
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的
思路
- 确定dp数组以及下标的含义:dp[j]凑足总金额为j所需钱币最少的个数是dp[j]
- 确定递推公式:得到dp[j]有两种来源,一种是放入硬币coins[i],另一种是不放入硬币coins[i],dp[j] = min(dp[j],dp[j - coins[i]] + 1)
- 关于dp数组的初始化:dp[0] = 0,然后其他的dp[j]都必须初始化为一个最大的数,防止在min(dp[j - coins[i]] + 1,dp[j])中被初始值覆盖
- 遍历顺序:先物品后背包还是先背包后物品都是可以的,本题不强调遍历顺序
代码
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
// 每一种硬币的数量是无限的,所以这是一道完全背包问题
// 初始化dp数组
vector<int> dp(amount + 1,INT_MAX);// 初始化最大值 防止被覆盖
dp[0] = 0;// 填充总金额为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)
{
// 放入硬币coins[i] 或者不放入硬币coins[i]
dp[j] = min(dp[j],dp[j - coins[i]] + 1);
}
}
}
if(dp[amount] == INT_MAX)
{
return -1;
}
else
{
return dp[amount];
}
}
};