完全背包问题 完全背包问题同01背包问题的区别主要再物品可以被重复使用,因此,在递推公式和遍历顺序上存在一定的差别。 可以采用二维数组完整得获取递推公式 遍历顺序如果采用二维数组的话,依然建议先物品,后背包的顺序进行遍历,但是因为不是一维数组,所以可以不用从大到小进行遍历。 518.零钱兑换问题II
class Solution {
public:
int change(int amount, vector<int>& coins) {
//可选择回溯算法和完全背包的动态规划,因为回溯算法超出时间复杂度,此处采用完全背包的动态规划
//先排除意外情况
// 边界情况:总金额为0,只有1种组合(不选任何硬币)
if (amount == 0) return 1;
// 边界情况:无硬币且金额>0,无法凑出
if (coins.empty()) return 0;
//背包容量即是amount
int bagSize=amount;
//设计dp数组,因为是可重复取硬币,这里采用二维数组
vector<vector<uint64_t>> dp(coins.size(), vector<uint64_t>(bagSize + 1, 0));
//初始化
//首先初始化列
for(int i=0;i<coins.size();i++){
dp[i][0]=1;
}
//初始化行
for(int i=0;i<=bagSize;i++){
if (i % coins[0] == 0) dp[0][i] = 1;
}
//执行递推公式
for(int i=1;i<coins.size();i++){//行,遍历硬币
for (int j = 0; j <= bagSize; j++) { // 列,遍历背包
if (coins[i] > j) dp[i][j] = dp[i - 1][j]; //硬币面值大于金额,无法使用该硬币,组合数 = 不用该硬币的组合数
else dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i]];// 组合数 = 不用该硬币的组合数 + 用至少1个该硬币的组合数(dp[i][j-coins[i]])
}
}
return dp[coins.size()-1][bagSize];
}
};
一维数组方式
class Solution {
public: int change(int amount, vector<int>& coins) {
// 1. 定义dp数组:dp[j] 表示「凑成总金额j的硬币组合数」
// 用uint64_t避免数值溢出(比如amount=500、coins多的场景,组合数会很大)
vector<uint64_t> dp(amount + 1, 0);
// 2. 初始化:凑金额0只有1种方式(不选任何硬币),这是所有组合的基础
dp[0] = 1;
// 3. 完全背包核心逻辑:先遍历物品(硬币),再遍历容量(金额),正序遍历容量(允许重复选)
for (int coin : coins) { // 遍历每一种硬币(物品)
// 正序遍历金额:从coin开始(金额至少能装下当前硬币),允许重复选同一硬币
for (int j = coin; j <= amount; j++) { // 状态转移:dp[j] = 原有组合数 + 加入当前硬币后的新组合数
// 新组合数 = 凑j-coin的组合数(先选1个当前硬币,剩下的j-coin随便凑)
dp[j] += dp[j - coin]; }
}
// 最终结果:凑成amount的组合数
return dp[amount];
}
};
377.组合总和IV 注意和上题相区别,上题零钱总和是只需要求组合,并不需要求排列,所以应当是先遍历物品,再遍历背包,但是这道题是需要求排列,所以应当是先遍历背包再遍历物品,两个问题的遍历顺序不同!!!
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
//动态规划求组合总和
//设计dp数组
vector<int> dp(target+1,0);
//初始化
dp[0]=1;//背包为0任有一种装填方式,就是不装填
//执行递推公式
//如果求组合数就是外层for循环遍历物品,内层for遍历背包。
//如果求排列数就是外层for遍历背包,内层for循环遍历物品。
for(int i=0;i<=target;i++){//遍历背包
for(int j=0;j<nums.size();j++){
if (i - nums[j] >= 0 && dp[i] <= INT_MAX - dp[i - nums[j]]) {
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
}
};