原题链接:322. 零钱兑换
solution:
一道完全背包问题模板题,amount相当于背包的体积,coins保存各个物品的体积,每个物品可以使用无限次,并且每个物品的价值为1,求解能塞满背包的最小价值。
状态表示:dp[i][j]:表示从前i个纸币中选,满足纸币总额为j的最小值的集合
状态计算: dp[i][j] = min(dp[i - 1][j],dp[i - 1][j - coins[i]] + 1,dp[i - 1][j - 2 * coins[i]] + 2..........)
同时dp[i][j - coins[i]] = min(dp[i - 1][j - coins[i]],dp[i - 1][j - 2 * coins[i]] + 1......................)
综上所述
转移方程:dp[i][j] = min(dp[i - 1][j],dp[i][j - coins[i]];
二维版本:
const int INF = 0x3f3f3f3f;
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<vector<int>> dp(n + 1, vector<int> (amount + 1));
for(int i = 1;i <= amount;i++) dp[0][i] = INF;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= amount;j++){
dp[i][j] = dp[i - 1][j];
if(j >= coins[i - 1]) dp[i][j] = min(dp[i][j],dp[i][j - coins[i - 1]] + 1);
}
return dp[n][amount] == INF? -1 : dp[n][amount];
}
};
一维优化:
const int INF = 0x3f3f3f3f;
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<int> dp (amount + 1);
for(int i = 1;i <= amount;i++) dp[i] = INF;
for(int i = 1;i <= n;i++)
for(int j = coins[i - 1];j <= amount;j++){
dp[j] = min(dp[j],dp[j - coins[i - 1]] + 1);
}
return dp[amount] == INF? -1 : dp[amount];
}
};