代码随想录算法训练营第四十四天| 01背包和完全背包的对比、LeetCode518.零钱兑换II、LeetCode377. 组合总和 Ⅳ、LeetCode70. 爬楼梯

完全背包和01背包的对比

01背包是一个物品只能用一次,完全背包则是可以用很多次,那么其主要差别就在递推公式这里。
01背包的二维递推公式如下:

dp[i][j] = max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]))

因为一个物品只能拿到一次,所以选到当前物品的状态只能是由选到上一个物品的状态决定的
而完全背包的递推公式如下:

dp[i][j] = max(dp[i-1][j],dp[i][j-weight[i]]+value[i])

因为一件物品可以反复拿到,因此和dp[i-1][j]对比的应该是dp[i][j-weight[i]]+value[i]
除此之外,遍历顺序也有不同,根据递推公式我们可以看出,01背包一维数组时,背包的遍历顺序一定是倒序,因为决定当前状态的时上一轮的左边的内容,但是完全背包的一维数组,决定当前状态的是当前的状态,所以一定要从前往后遍历。
此外在背包和物品的遍历顺序上也有讲究,因为01背包一个物品只能出现一次,所以不需要考虑这些出现的顺序和次数。
但是在完全背包中,如果需要考虑有多少种方案,而不是最大能装多少,那么遍历顺序就有讲究了,如果先遍历物品再遍历背包,那么就是组合问题,{1,5}会出现但是不会出现{5,1},但如果先遍历背包再遍历物品,就会出现{1,5}和{5,1},这就是排列问题,如果需要考虑排列,就要先遍历背包。这种组合问题只会在完全背包中产生,二维的dp数组是无法解决完全背包中的排列问题的。

518.零钱兑换II

题目描述: 518.零钱兑换II.

解法

二维dp
class Solution(object):
    def change(self, amount, coins):
        dp = [[0] * (amount + 1) for _ in range(len(coins)+1)]
        for i in range(len(coins)+1):
            dp[i][0] = 1
        for i in range(1,len(coins)+1):
            for j in range(amount+1):
                dp[i][j] = dp[i-1][j]
                if j >= coins[i-1]:
                    dp[i][j] += dp[i][j-coins[i-1]]
        return dp[len(coins)][amount]

如果使用二维数组时,一定要注意如何初始化,那么当金钱额度为0的时候,方案就只有1,那就是什么都不选。如果可选的金钱是0,那么可选的方案也一样是0。

滚动dp
class Solution(object):
    def change(self, amount, coins):
        dp = [0] * (amount+1)
        dp[0] = 1
        for i in range(len(coins)):
            for j in range(coins[i],amount+1):
                dp[j] += dp[j-coins[i]]
        return dp[amount]

377. 组合总和 Ⅳ

题目描述: 377. 组合总和 Ⅳ.

解法

滚动dp
class Solution(object):
    def combinationSum4(self, nums, target):
        dp = [0] * (target+1)
        dp[0] = 1
        for j in range(target+1):
            for i in range(len(nums)):
                if j >= nums[i]:
                    dp[j] += dp[j-nums[i]]
        return dp[target]

这就体现了不同的方法,如果是求不同的排列方法,那就要先遍历背包了。

二维dp(二维dp好像做不了排列问题,只能做组合问题)
class Solution(object):
    def combinationSum4(self, nums, target):
        dp = [[0] * (target+1) for _ in range(len(nums)+1)]
        dp[0][0] = 1
        for j in range(target+1):
            for i in range(1,len(nums)+1):
                dp[i][j] = dp[i-1][j]
                if j >= nums[i-1]:
                    dp[i][j] += dp[i][j-nums[i-1]]
        return dp[len(nums)][target]

70. 爬楼梯

题目描述: 70. 爬楼梯.

解法

爬楼梯也是一种完全背包,而且是完全背包中排列问题,所以就先遍历背包再遍历物品。

滚动dp
class Solution(object):
    def climbStairs(self, n):
        step = [1,2]
        dp = [0] * (n+1)
        dp[0] = 1
        for j in range(n+1):
            for i in range(len(step)):
                if j>=step[i]:
                    dp[j] += dp[j-step[i]]
        return dp[n]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值