思路:01背包问题(从右向左写)
题目可以转化为:在nums数组中找出一些元素,这些元素的和为sum/2,由于每个元素只能选一次,所以等价于0-1背包问题(传统的01背包的限制是背包容量有限,这道题的限制是和为固定值)
具体细节:
dp[i][j]表示:下标i前面所有的元素是否能组成j
转移方程:dp[i][j] = dp[i - 1][j - nums[i]] || dp[i - 1][j] (选nums[i] 不选nums[i] 两个中有一个构成即可,所以用逻辑运算符’||')
边界:dp[0][0] = true 其他都是false
特例判别:
1:数组中所有元素的和sum为奇数时 return false
2:数组中只有一个元素时 return false
3:数组中元素的最大值 大于 sum/2 return false
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0), n = nums.size();
if (sum & 1 || n < 2) return false;
if (*max_element(nums.begin(), nums.end()) > sum / 2) return false;
vector<int> dp(sum / 2 + 1, false);
dp[0] = true;
for (int i = 0; i < n; ++i) {
for (int j = sum / 2; j >= nums[i]; --j) {
dp[j] = dp[j - nums[i]] || dp[j];
}
}
return dp[sum / 2];
}
};
思路2:hash
易错点:在遍历hash时,要先备份原hash一份:hash2,在hash2上面遍历,插入到hash。因为在同一个hash里面操作的话可能会导致迭代器失效。