代码随想录算法训练营-动态规划-3-(0-1背包问题)|416. 分割等和子集、1049. 最后一块石头的重量 II
01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。
1 class Solution: 2 def canPartition(self, nums: List[int]) -> bool: 3 _sum = 0 4 5 # dp[i]中的i表示背包内总和 6 # 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200 7 # 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了 8 dp = [0] * 10001 9 for num in nums: 10 _sum += num 11 # 也可以使用内置函数一步求和 12 # _sum = sum(nums) 13 if _sum % 2 == 1: 14 return False 15 target = _sum // 2 16 17 # 开始 0-1背包 18 for num in nums: 19 for j in range(target, num - 1, -1): # 每一个元素一定是不可重复放入,所以从大到小遍历 20 dp[j] = max(dp[j], dp[j - num] + num) 21 22 # 集合中的元素正好可以凑成总和target 23 if dp[target] == target: 24 return True 25 return False
本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。
1 class Solution: 2 def lastStoneWeightII(self, stones: List[int]) -> int: 3 dp = [0] * 15001 4 total_sum = sum(stones) 5 target = total_sum // 2 6 7 for stone in stones: # 遍历物品 8 for j in range(target, stone - 1, -1): # 遍历背包 9 dp[j] = max(dp[j], dp[j - stone] + stone) 10 11 return total_sum - dp[target] - dp[target]