思路是尽可能分成重量相等的两堆,也就是取总和一半的的背包容量,装最大重量
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
_sum = sum(stones)
val = _sum // 2
dp = [0] * (val + 1) #dp数组的含义为从石头中任取,装满容量为_sum//2的背包的最大重量,因为只有尽量装满_sum//2 剩下的一堆石头和背包里的石头就是最接近的
for i in range(len(stones)):
for j in range(val, stones[i] - 1, -1):
dp[j] = max(dp[j], dp[j - stones[i]] + stones[i])
return _sum - 2 * dp[val]
dp数组的含义为从石头中任取,装满容量为_sum//2的背包的最大重量,因为只有尽量装满_sum//2 剩下的一堆石头和背包里的石头就是最接近的
能想到在nums中任取来装满容量为(sum(nums) - target)/2的背包,这些值需要变为负值
但是不知道该怎么求最大的方法数量
dp[j] 数组含义表示装满容量为j的背包有dp[j]种方法
装满容量为j的背包的总方法数量等于所有装满容量为j-nums[i]的背包方法数量之和。其中num[i]表示第i个物品的重量。
class Solution:
def findTargetSumWays(self, nums: List[int], target: int) -> int:
val = (sum(nums) - target) / 2 #在数组中哪些需要变为负值的元素和
if val != int(val) or val < 0: #如果这个和小于0或不为整数,说明找不到
return 0
val = int(val)
dp = [0] * (val + 1) #dp数组含义,装满容量为j的背包有多少种方法
dp[0] = 1
for i in range(len(nums)):
for j in range(val, nums[i] - 1, -1):
dp[j] += dp[j - nums[i]] #递推公式很关键,所有的装满背包最多有多少种方法问题通用
return dp[val]
有一点思路:每个字符串就是一个物品,物品的价值就是1,有两个重量,一个重量就是0的数量 另一个重量就是1的数量。背包的容量也分为两部分。要同时装满背包的两个属性,求最大的价值,也就是子集最大的数量。
dp[i][j]: 装满i个0 j个1最多装多少个(dp[i][j])物品,最后返回dp[m][n]
class Solution:
def findMaxForm(self, strs: List[str], m: int, n: int) -> int:
#dp[i][j] 最多有i个0和j个1的strs的最大子集的大小 m和n是背包容量,双容量
#dp[i][j] = max(dp[i][j], dp[i - num_0][j - num_1] + 1)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for st in strs: #遍历物品
num_0 = st.count('0') #count来统计0字符的个数
num_1 = st.count('1') #1字符的个数
for i in range(m, num_0 - 1, -1): #遍历背包容量1
for j in range(n, num_1 - 1, -1): #遍历背包容量2
dp[i][j] = max(dp[i][j], dp[i - num_0][j - num_1] + 1)
return dp[m][n]