leetcode 416. 分割等和子集
分析 :
首先本题可以将判断这个数组是否可以分割成两个子集的问题转换为集合中是否存在和为sum/2
的子集,这里的sum
是数组所有元素的和,可以发现这是一个0-1背包问题,因为每个元素只能使用一次。
- 这里的物品是数组元素,
nums[i]
既是物品的重量也是物品的价值,sum/2
是背包的容量 - 如果
sum
是个奇数,可以直接返回false
;
解题:
-
计算得到背包的容量大小
target = sum / 2
; -
确定
dp
数组的定义,将dp[i]
定义为是否存在子集和为i的子集; -
初始化
dp
数组的元素都为false
,dp[0]
为true
;vector<bool> dp(target + 1, false); dp[0] = true;
-
确定
dp
数组的更新方式- 情况1:如果
dp[j - nums[i]]
为true
,即存在和为j - nums[i]
的子集,nums[i]
存在,肯定也存在和为j - nums[i] + nums[i]
的子集,即存在和为j
的子集; - 情况2:已经存在子集和为
j
的子集了,即dp[j]
为真
更新公式:
dp[j] = dp[j] || dp[j - nums[i]];
- 情况1:如果
完整代码:
bool canPartition(vector<int>& nums) {
int sum = 0;
int n = nums.size();
for (int i : nums) {
sum += i;
}
if (sum % 2) return false;
int target = sum / 2;
vector<bool> dp(target + 1, false);
dp[0] = true;
for (int i = 1; i < n; i++) {
for (int j = target; j >= nums[i]; j--) {
dp[j] = dp[j] || dp[j - nums[i]];
}
}
return dp[target];
}