leetcode 518.完全背包
完全背包
思路
朴素解法:
- 状态划分
- f(i,j):前i个物品凑成数量j的组合数
- 状态转移
- 分析:第i个物品可以选或者不选,若不选则没有新增组合数,若选择则组合数增加,即最小的情况就是不选
- 因此:f[i][j] = f[i-1][j] + sum(f[i-1][j - k*value]) , k >= 1, k * val <= j
代码
class Solution {
int dp[305][5005];
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
for(int i = 0;i <= n;i++) dp[i][0] = 1;
for(int i = 1;i <= coins.size();i++){
for(int j = 0;j <= amount;j++){
dp[i][j] = dp[i-1][j];
for(int k = 1;k * coins[i-1] <= j;k++){
// 这里的状态转移是由上一轮得到的,所以要进行累和
dp[i][j] += dp[i-1][j - k * coins[i-1]];
}
}
}
return dp[n][amount];
}
};
思路
时间优化:
在朴素解法的基础上,可以将k省去
因为在朴素解法中,每次第i维的状态,都是由第i-1维的状态转移过来的,实际上可以使用第i维来转移。由于dp[i][j - value]其实就是 sum(dp[i-1][j-k*value])
则可以得到更简洁的状态转移方程:
- f[i][j] = f[i-1][j] + f[i][j-value]
代码
class Solution {
int dp[305][5005];
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
for(int i = 0;i <= n;i++) dp[i][0] = 1;
for(int i = 1;i <= n;i++){
for(int j = 0;j <= amount;j++){
dp[i][j] = dp[i-1][j];
if(j - coins[i-1] >= 0) dp[i][j] += dp[i][j-coins[i-1]];
}
}
return dp[n][amount];
}
};
思路:
空间优化:
空间优化就非常简单了,直接把第一维去掉就好了,因为每次第i维j列的数据,都是由j列前的数据得到的,用一维模拟这个过程完全没有歧义
代码:
class Solution {
int dp[5005];
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
dp[0] = 1;
for(int i = 1;i <= n;i++){
for(int j = coins[i-1];j <= amount;j++){
dp[j] += dp[j-coins[i-1]];
}
}
return dp[amount];
}
};
浙公网安备 33010602011771号