目录
1.分割等和子集

对于这道题,我们可以先计算数组的总和,如果总和为奇数的话,就不需要后面的判断了,奇数和肯定无法分割等和子集
和sum为偶数后,我们可以将其看作一个背包问题,我们需要从数组中找到和为sum/2的数组,所以我们就将其转化为背包问题
设dp[i][j]表示能否从前i个数字中找到和为j的数组,分为以下情况:
- 选择i这个数,dp[i][j] = dp[i - 1][j - nums[i]]
- 不选择i这个数,dp[i][j] = dp[i - 1][j]
我们取这两种结果的或运算,只要满足一种即可
cpp
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size(), sum = 0;
for(auto x : nums) sum += x;
if(sum % 2 == 1) return false;
int aim = sum / 2;
vector<vector<bool>> dp(n + 1, vector<bool>(aim + 1));
for(int i = 0; i <= n; i++) dp[i][0] = true;
for(int i = 1; i <= n; i++)
for(int j = 0; j <= aim; j++)
{
dp[i][j] = dp[i - 1][j];
if(j >= nums[i - 1])
dp[i][j] = dp[i][j] || dp[i - 1][j - nums[i - 1]];
}
return dp[n][aim];
}
};
空间优化后
cpp
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size(), sum = 0;
for(auto x : nums) sum += x;
if(sum % 2 == 1) return false;
int aim = sum / 2;
vector<bool> dp(aim + 1);
dp[0] = true;
for(int i = 1; i <= n; i++)
for(int j = aim; j >= nums[i - 1]; j--)
dp[j] = dp[j] || dp[j - nums[i - 1]];
return dp[aim];
}
};