第一类问题:计算能不能装满
采用一维滚动数组:
1. 从后向前遍历
2.dp[j] = max(dp[j],dp[j-value[i]+value[i])
#分别代表不选与选
3. 先遍历物品再遍历背包。遍历背包时有条件要求
4. 根据dp函数进行初始化,全为0
class Solution(object):
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
if sum(nums) % 2 != 0:
return False
tag = sum(nums)//2
dp = [0] * (tag+1)
for i in range(len(nums)):
for j in range(tag,nums[i]-1 , -1):
dp[j] = max(dp[j], dp[j-nums[i]] + nums[i])
return dp[tag]==tag
核心是转换问题,细节与上一题一样,
class Solution(object):
def lastStoneWeightII(self, stones):
"""
:type stones: List[int]
:rtype: int
"""
target = sum(stones)//2
dp = [0] * (target+1)
for stone in stones:
for j in range(target,stone-1,-1):
dp[j] = max(dp[j],dp[j-stone]+stone)
return sum(stones)-2*dp[target]
第二类问题
计算装满背包有多种方法
left - right = tgt
left + right = sum_nums
left = (sum + tgt)/2
求装满left容量的背包有多少种方法
dp[j] = dp[j] +dp[j-nums[i]]
dp[0] =1 因为背包容量为0 只有一种装法---什么都不装
class Solution(object):
def findTargetSumWays(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
total_sum = sum(nums)
if abs(target) > total_sum: return 0
if (target + total_sum) % 2 ==1: return 0
target_sum = (target + total_sum) // 2
dp = [0] * (target_sum + 1)
dp[0] = 1
for num in nums:
for j in range(target_sum, num-1,-1):
dp[j] += dp[j-num]
return dp[target_sum]
二维dp数组问题(本质上是三维)
dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]。
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
因为是子集个数,不选--不变,选了子集个数+1
class Solution(object):
def findMaxForm(self, strs, m, n):
"""
:type strs: List[str]
:type m: int
:type n: int
:rtype: int
"""
dp = [[0] * (n+1) for _ in range(m+1)]
for string in strs:
zero = string.count('0')
one = len(string) - zero
for i in range(m,zero-1,-1):
for j in range(n,one-1,-1):
dp[i][j] = max(dp[i][j],dp[i-zero][j-one]+1)
return dp[m][n]