好久不见~
我一开始看到,元素和是一个定值嘛,我觉得可以转换成LeetCode40 组合总和II,找nums里面和为一个定值的元素,就写了回溯,结果超时了
class Solution {
public:
bool recall(int cnt, int sum, map<int, int> appearNumber, vector<int> nums)
{
if (sum == 0) return true;
if (sum < 0) return false;
if (cnt >= nums.size()) return false;
for (int i = 1; i <= appearNumber[nums[cnt]]; i++)
{
if (recall(cnt + appearNumber[nums[cnt]], sum - i * nums[cnt], appearNumber, nums) == true)
{
return true;
}
}
if (recall(cnt + appearNumber[nums[cnt]], sum, appearNumber, nums) == true)
{
return true;
}
return false;
}
bool canPartition(vector<int>& nums) {
sort(nums.begin(), nums.end());
map<int, int> appearNumber;
int size = nums.size();
appearNumber[nums[0]] = 1;
int sum = nums[0];
for (int i = 1; i < size; i++)
{
sum += nums[i];
if (nums[i] == nums[i - 1])
{
appearNumber[nums[i]]++;
}
else
{
appearNumber[nums[i]] = 1;
}
}
// 注意map的遍历
// map<int, int>::iterator it;
// for (it = appearNumber.begin(); it != appearNumber.end(); it++)
// {
// printf("%d %d\n", it->first, it->second);
// }
if (sum % 2 != 0) return false;
sum /= 2;
if (nums[size - 1] > sum) return false;
else if (nums[size - 1] == sum) return true;
return recall(0, sum, appearNumber, nums);
}
};
标准解法是dp嘛,在序列中选取若干个数,让它们的和刚好等于一个给定值。【如果经验丰富的话这里应该能看出来是01背包问题】
class Solution {
public:
bool canPartition(vector<int>& nums) {
int size = nums.size();
if (size == 1) return false;
int sum = nums[0];
int maxNum = nums[0];
for (int i = 1; i < size; i++)
{
sum += nums[i];
if (nums[i] > maxNum)
{
maxNum = nums[i];
}
}
if (sum % 2 != 0) return false;
sum /= 2;
if (maxNum > sum) return false;
else if (nums[size - 1] == sum) return true;
bool f[size][sum + 1];
memset(f, false, sizeof(f));
//f[0][nums[0]] = true;
for (int i = 0; i < size; i++)
{
f[i][nums[i]] = true;
f[i][0] = true;
}
for (int i = 1; i < size; i++)
{
for (int j = 1; j <= sum; j++)
{
if (j >= nums[i])
{
f[i][j] = f[i - 1][j - nums[i]] | f[i - 1][j];
}
else
{
f[i][j] = f[i - 1][j];
}
}
}
return f[size - 1][sum];
}
};