完全背包和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]