dp完全背包问题解组合问题——零钱兑换

在这里插入图片描述
本题为完全背包问题,遍历容量需要顺序遍历

class Solution {
public:
   int change(int amount, vector<int>& coins) {
        // 完全背包  顺序遍历
        // 背包容量为amount
        int n = coins.size();
        // dp[i][j]:有coin[0]...coin[i]这i+1个硬币,凑出amount,有dp[i][j]种方法
        vector<vector<int>> dp(n, vector<int>(amount + 1, 0));
        dp[0][0] = 1;
        for(int j = 1; j <= amount; j++){
            // 只有coins[0]一枚硬币,若能整除,则只有1种方法凑出j,若不能整除,则不能凑出j
            dp[0][j] = (j % coins[0] == 0) ? 1 : 0;
        }
        // 遍历硬币
        for(int i = 1; i < n; i++){
            // 遍历面值
            for(int j = 0; j <= amount; j++){
                if(j < coins[i]){
                    // 当前面值 < 当前硬币,无法使用当前硬币,依然使用前0~i-1种硬币凑出面值j
                    dp[i][j] = dp[i-1][j];
                }else{
                    // 当前面值 >= 当前硬币
                    // dp[i-1][j]表示不使用当前硬币凑出j的方法数
                    // dp[i][j-coins[i]]则表示使用至少使用一枚coins[i]硬币凑出j,完全背包,使用本层计算结果
                    // 这里不能是dp[i-1][j-coins[i]],因为这表示只使用一枚coins[i]凑出面值j
                    dp[i][j] = dp[i-1][j] + dp[i][j-coins[i]];
                }
            }
        }
        return dp[n-1][amount];
    }
};
class Solution {
public:
    int change(int amount, vector<int>& coins) {
        // 完全背包  顺序遍历
        // 背包容量为amount
        int n = coins.size();
        // dp[j]:使用前i钟货币凑出j,有dp[j]种方法
        vector<int> dp(amount + 1, 0);
        dp[0] = 1;
        // 遍历硬币
        for(int i = 0; i < n; i++){
            // 遍历面值
            for(int j = coins[i]; j <= amount; j++){
                dp[j] = dp[j] + dp[j-coins[i]];
            }
        }
        return dp[amount];
    }
};

在这里插入图片描述
01背包 —> 逆序
完全背包 —> 顺序
组合 —> 先遍历物品
排列 —> 先遍历容量

class Solution {
public:
	int coinChange(vector<int>& coins, int amount) {
        // 完全背包---> 顺序
        // 组合 ---> 先遍历物品
        vector<int> dp(amount + 1, amount + 1);
        dp[0] = 0;
        for(int i = 0; i < coins.size(); i++){
            for(int j = coins[i]; j <= amount; j++){
            	// 不使用coins[i],使用coins[i]
            	// 用dp[j-coins[i]]个硬币凑出j-coins[i],再用1个coins[i]凑出coins[i]
            	// dp[j-coins[i]]在二维数组中使用的是本层数据,表示使用0...i种货币凑出j-coins[i],再用1个coins[i]凑出coins[i]
            	// 这样dp[j-coins[i]]+1就能表示至少使用1个coins[i],凑出j,所需要的货币数量
                dp[j] = min(dp[j], dp[j-coins[i]] + 1); 
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值