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];
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性