day37 代码随想录 | 完全背包问题 组合总和 II 零钱兑换II 爬楼梯(进阶版)

完全背包问题基础

完全背包问题是在0-1背包问题的上的基础得来的,区别在于在于物品可以无限制的重复选择。

有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。

完全背包和01背包问题唯一不同的地方就是,每种物品有无限件

这里的循环是从小到大的,因为我们可以重复选择物品

在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的!

零钱兑换 II

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。 

题目数据保证结果符合 32 位带符号整数。

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

这个就是一个完全背包问题,但是需要注意,这里其实求的是组合数

也就是说,你凑成5 2 2 1 和 1 2 2 是等价的! 为什么要分辨这个呢,

因为这个关系到遍历顺序,到底是物品是内循环还是外循环。

如果物品是内循环,容量是外循环,那么你就是将  2 2 1 和 1 2 2 当初两种不同的方式。

同时,遍历5部曲

1. 确定dp数组定义

dp[j] 凑成总金额j的货币组合数为dp[j]

2. 递推公式

组合 就是需要累加 dp[j] += dp[j - coins[i]];

3. dp数组如何初始化

首先dp[0]一定要为1,dp[0] = 1是 递归公式的基础。如果dp[0] = 0 的话,后面所有推导出来的值都是0了。

4. 确定遍历顺序

这是本题的关键

如果物品是外循环,算的是组合数,因此你每个物品只是被计算一次

如果物品是内循环,算的是排列数,背包的每一个值,都会过物品

class Solution:
    def change(self, amount: int, coins: List[int]) -> int:
        dp = [0] * (amount + 1)

        dp[0]  = 1

        for i in range(len(coins)):
            for j in range(1, amount + 1):
                if coins[i] <= j:
                    dp[j] += dp[j-coins[i]]
        return dp[amount] 

377. 组合总和 Ⅳ

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

这个题就是求排列了,我们需要修改遍历顺序。 物品要在内循环

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        # 这个就是求排列 遍历顺序不一样
        dp = [0] * (target + 1)
        dp[0] = 1
        for j in range(1, target + 1):
            for i in range(len(nums)):
                if nums[i] <= j:
                    dp[j] += dp[j-nums[i]]

        return dp[target]

70. 爬楼梯(进阶版)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

输入描述:输入共一行,包含两个正整数,分别表示n, m

输出描述:输出一个整数,表示爬到楼顶的方法数。

输入示例:3 2

输出示例:3

提示:

当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。

此时你有三种方法可以爬到楼顶。

  • 1 阶 + 1 阶 + 1 阶段
  • 1 阶 + 2 阶
  • 2 阶 + 1 阶

这个题其实就是完全背包求排列数,和上面的题类似

n是容量, m是物品个数

def stairsPlus():
    n, m = [int(x) for x in input().split()]
    
    dp = [0] * (n + 1)
    dp[0] = 1
    for j in range(1, n+1):
        for i in range(1, m+1):
            if i <= j:
                dp[j] += dp[j-i]
    return dp[n]

if __name__ == "__main__":
    print(stairsPlus())

  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值