题意
给定一个序列,将序列中的元素分为两组,要求这两组的和相同。
思路
两个数组和相同,即相减为0:若元素加入第一组,那么我们记为+,加入第二组,我们记为-,只需要最后的和为0即可。
状态表示:d[i][j],选到第i个元素,和为j时是否成立。
转移方程:d[i][j]=d[i−1][j−ai]||d[i−1][j+ai]
时间复杂度:O(sum)sum=∑iai
空间复杂度:O(sum)需要开四倍大小的空间
细节
需加上偏移量避免数组下标为负数
代码
const int maxn = 80005;
bool d[2][maxn];
const int ofs = 40000;
class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
if (n == 0) return true;
int hb = 0;
for (int i = 0; i < n; i++) hb += nums[i];
int lb = -hb;
for (int j = lb; j <= hb; j++) d[0][j + ofs] = false;
d[0][nums[0] + ofs] = d[0][-nums[0] + ofs] = true;
int t = 0;
for (int i = 1; i < n; i++, t ^= 1) {
for (int j = lb; j <= hb; j++) {
d[t ^ 1][j + ofs] = (d[t][j - nums[i] + ofs] || d[t][j + nums[i] + ofs]);
}
}
return d[t][0 + ofs];
}
};