159、【动态规划】leetcode ——322. 零钱兑换:二维数组+一维滚动数组(C++/Python版本)

文章介绍了如何使用动态规划方法解决322.零钱兑换问题,包括二维数组和一维滚动数组两种解法。通过初始化dp数组,遍历硬币种类和总额,找到组合硬币的最小数量。当无法找到解决方案时返回-1。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解题思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
原题链接:322. 零钱兑换

解题思路

(1)二维数组

  • 动态规划五步曲:

(1)dp[i][j]含义: 在总额为j的前提下,从coins[0]-coins[i]中选择硬币,可用最少硬币组成的j的硬币个数。

(2)递推公式: dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i]]),完全背包递推公式取最小值

(3)dp数组初始化: 因为要求的是最小值,因此dp[i][0] = 0, 表示为总价值为0时什么都不选,其余都初始化为INT_MAX。当只有找当j - coins[i]为0的数,才会因为min()更新,如果减去的不为0,或者减去到之前没有被更新过的数,则还会保持INT_MAX。

(4)遍历顺序: 因为只要找到某种最小值的方案取的是MIN,因此先背包后物品,先物品后背包都可以。

(5)举例: (省略)

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        // 因为需要都初始化为INT_MAX,数组用memset都会转化成8bit无符号数,不方便
        vector<vector<int>> dp(n + 1, vector<int>(amount + 1,INT_MAX));     
        for(int i = 0; i <= n; i++)         dp[i][0] = 0;
        
        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= amount; j++) {                                                
                if(coins[i - 1] <= j && dp[i][j - coins[i - 1]] != INT_MAX) {
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i - 1]] + 1);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }                    
            }
        }
        // 当为amount时为INT_MAX,说明在递推公式时二者都没有可以对应拼凑出的结果,返回-1
        return dp[n][amount] == INT_MAX ? -1 : dp[n][amount];
    }
};

Python

class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        n = len(coins)
        dp = [[inf] * (amount + 1) for _ in range(n + 1)]
        for i in range(n + 1):
            dp[i][0] = 0
        
        for i in range(n + 1):
            for j in range(amount + 1):
                if coins[i - 1] > j:
                    dp[i][j] = dp[i - 1][j]
                else:
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - coins[i - 1]] + 1)
        
        return -1 if dp[n][amount] == inf else dp[n][amount]

(2)一维滚动数组

将递推公式转化为等价式dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1),初始化与之相同,遍历顺序按完全背包滚动数组方式从小到大。

举例:
image.png

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        // 因为需要都初始化为INT_MAX,数组用memset都会转化成8bit无符号数,不方便
        vector<int> dp(amount + 1,INT_MAX);
        dp[0] = 0;        
        
        for(int i = 1; i <= n; i++) {
            for(int j = coins[i - 1]; j <= amount; j++) {                                                
                if(dp[j - coins[i - 1]] != INT_MAX) {
                    dp[j] = min(dp[j], dp[j - coins[i - 1]] + 1);
                }  
            }
        }

        return dp[amount] == INT_MAX ? -1 : dp[amount];
    }
};

参考文章:322. 零钱兑换

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

辰阳星宇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值