【力扣100】【好题】322.零钱兑换 || 01背包&完全背包

时间:2024-03-10 20:49:56

添加链接描述
思路:

  1. dp[j]数组表示的是在金额达到 j 的时候所需要的最小硬币数
  2. 金额:背包容量,每个硬币的个数都为1:背包中物品的价值,硬币面额:物品重量
  3. dp[j]=min(dp[j],dp[j-coin]+1)
class Solution:
    def coinChange(self, coins: List[int], amount: int) -> int:
        dp = [float('inf')] * (amount + 1)
        dp[0] = 0
        
        for coin in coins:  # 遍历硬币
            for j in range(coin, amount + 1):  # 遍历金额
                dp[j] = min(dp[j], dp[j - coin] + 1)

        if dp[amount] == float('inf'):
            return -1
        return dp[amount]

01背包(物品有限个数)

1.dp数组含义

dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

2.dp数组的初始化

在这里插入图片描述

  1. 首先设置dp数组为全0
  2. dp[i][0]全部设置为0(容量为0时背包里无价值)
  3. 第一行也就是dp[0][j]两种情况:
  • 当前容量j<weight[0]时,设置为0(理解为放不下,初始化的时候设置全0,这一部可以跳过)
  • wight[0]<=bagweight时,设置为weight[0](理解为可以放下)
  • for (int j = weight[0]; j <= bagweight; j++) { dp[0][j] = value[0]; }
3.递推公式
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
4.遍历顺序

先遍历物品再遍历重量

for(int i = 1; i < weight.size(); i++) { // 遍历物品,从1开始因为第0行已经被初始化
    for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
        if (j < weight[i]) dp[i][j] = dp[i - 1][j];  // 放不下当前这个物品
        //  可以放下当前这个物品
        else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    }
}

滚动数组

for i in range(len(weight)):  # 遍历物品
    for j in range(bagWeight, weight[i] - 1, -1):  # 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i])

完全背包(物品无限个数)

for i in range(len(weight)):  # 遍历物品
    for j in range(weight[i], bagWeight + 1):  # 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i])