【LeetCode-416】分割等和子集
问题
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
解答1:背包问题模版
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0, n = nums.size();
for (int i : nums) sum += i;
if (sum % 2 != 0) return false;
sum /= 2;
int dp[sum + 1]; memset(dp, 0, sizeof dp);
for (int i = 0; i < n; i++)
for (int j = sum; j >= nums[i]; j--)
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
return dp[sum] == sum;
}
};
重点思路
本题的重点为如何将问题转化为01背包问题。两个子集元素和相同,可将本问题转化为是否存在一个元素子集,使得其加和为总体的一半。我们可以将本问题继续转化为背包问题的经典形式:求满足该容量下,能装下的最大的价值是多少。本问题中价值为该元素自身的值。当最后背包容量为总元素加和的一半,且该背包被装满了,那么满足题目要求。
解答2:更简洁的状态方程
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0, n = nums.size();
for (int num : nums) sum += num;
if (sum % 2 != 0) return false;
sum /= 2;
bool dp[sum + 1]; memset(dp, 0, sizeof(dp));
dp[0] = true;
for (int i = 0; i < n; i++)
for (int j = sum; j >= nums[i]; j--)
dp[j] |= dp[j - nums[i]];
return dp[sum];
}
};
重点思路
根据方法1中的分析可知,当背包在上一个阶段没有被装满,那当前阶段也不可能被装满,所以能直接使用一个布尔值来表示最终结果。