416. 分割等和子集
1. first idea
这实际上是一个典型的01背包,
一开始我觉得情况有些复杂,两个子数组要互相协调,比较难控制。
但是我在拖地的时候突然想到这实际上是一个固定量:。
我们可以把这个问题看作一个01背包的拓展:
- 背包的初始剩余容量是;
- 每个元素是一个物品,每个物品的重量是,价格和重量相等,因为我们需要追求在half限制条件下尽可能装满背包;
- 我们的目标是从
nums中选取物品,直到装满half,或者直到没有足够的剩余容量装任何剩余物品。
2. doc reading
代码随想录 (programmercarl.com) 所以基于这一思路,我们开始实现。
dp[i][j]表示前0~i号物品,背包当前临时容量为j的情况下,背包最大价值总和。(当前临时容量是我们假设的子情况,也就是假设背包的容量不是真实的总容量,而是j。)
递推式:
其中dp[i - 1][j - weights[i]]表示刨去当前选择要装入背包的第i号物品重量后,剩下的临时容量j-weights[i]]在前0~i-1号物品挑选后的最大价值。
初始化: 正如01背包初始化,我们对dp的左边列,也就是当前临时容量为0的列,赋值0,对第一行只遍历0号物品的总价值赋值。
最后看右下角遍历完所有物品后的,且背包当前临时容量为真实容量half的情况下,总的价值。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
values = weights = nums
if (sum(nums) % 2) == 1:
return False
half = sum(nums) // 2
dp = [[0] * (half + 1) for _ in range(len(nums))]
for bag_tmp_contain in range(weights[0], half + 1):
dp[0][bag_tmp_contain] = values[0]
for ob_idx in range(1, len(nums)):
# 遍历每一个物品
for bag_tmp_contain in range(0, half + 1):
# 遍历背包临时容量
if bag_tmp_contain < weights[ob_idx]:
dp[ob_idx][bag_tmp_contain] = dp[ob_idx - 1][bag_tmp_contain]
else:
dp[ob_idx][bag_tmp_contain] = max(
dp[ob_idx - 1][bag_tmp_contain],
dp[ob_idx - 1][bag_tmp_contain - weights[ob_idx]] + values[ob_idx]
)
return dp[-1][-1] == half