# 2021.9.6 buckle - split and subset

The first question of 0-1 knapsack application is also the first question at the beginning of school. To tell you the truth, it would be difficult for me to think about this topic if I hadn't already reminded that it is the application of 0-1 backpack, and I still couldn't think of it in the end.

Title Description:

Here you are   Contains only positive integers   of   Non empty   array   nums  . Please judge whether this array can be divided into two subsets so that the sum of the elements in the two subsets is equal.

Method 1:

```class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
if (n == 1)     //There is only one element, which must not be separated
{
return false;
}
int sum = 0;
int maxnum = INT_MIN;
for (int i = 0; i < n; i++)
{
sum += nums[i];
maxnum = max(maxnum, nums[i]);
}
if (sum % 2 != 0 || maxnum > sum / 2)   //If the sum of elements in the array is odd, it must not be split; If there is an element greater than half of the sum of elements, it must not be split
{
return false;
}
vector<vector<int>> f(n , vector<int>(sum / 2 + 1 , false));
//f[i][j] indicates whether the sum of some elements is equal to j for elements with subscript 0 - i. If yes, it is true; otherwise, it is false

f[nums] = true; //Initializes an element with a subscript of 0 whose value is equal to nums

for (int i = 1; i < n; i++)
{
for (int j = 1; j <= sum / 2; j++)
{
if (j < nums[i])
{
f[i][j] = f[i - 1][j];
//If J < nums[i], whether the sum of some elements (certainly no nums[i]) is equal to j is equivalent to considering only the elements with subscript 0 - i-1
}
else if (j == nums[i])
{
f[i][j] = true;
//In special cases, f[i][j] is also true when num [i] is exactly equal to j
}
else if (j > nums[i])
{
f[i][j] = f[i - 1][j] || f[i - 1][j - nums[i]];
//The former means not taking num [i], and the latter means taking num [i]
}
}
}
return f[n - 1][sum / 2];
}
};```

About why you can use 0-1 backpack: Because the solution of the first problem is not easy to understand, I use the solution of the second problem.

Let f[i][j] indicate whether the sum of some elements is equal to j for elements with subscript 0 - i. If yes, it is true; otherwise, it is false. Then, for nums[i], there are two cases: if nums[i] is taken, f[i][j] = f[i-1][j]; If nums[i] is not taken, then f[i][j] = f[i-1][j-nums[i]]. That is, f[i][j] = f[i-1][j] | f [I-1] [j-nums[i]].

However, the size relationship between J and nums[i] must also be considered: ① if J < nums[i], it means that there can be no element sum equal to j when considering nums[i], so f[i][j] = f[i-1][j]; ② If j==nums[i], it means that a single element is exactly equal to j, which is also true. This is a special case and needs to be considered separately; ③ If J > nums[i], then the above f[i][j] = f[i-1][j] 𞓜 f [I-1] [j-nums[i]].

So there are the following codes:

```                if (j < nums[i])
{
f[i][j] = f[i - 1][j];
//If J < nums[i], whether the sum of some elements (certainly no nums[i]) is equal to j is equivalent to considering only the elements with subscript 0 - i-1
}
else if (j == nums[i])
{
f[i][j] = true;
//In special cases, f[i][j] is also true when num [i] is exactly equal to j
}
else if (j > nums[i])
{
f[i][j] = f[i - 1][j] || f[i - 1][j - nums[i]];
//The former means not taking num [i], and the latter means taking num [i]
}```

First initialize all elements in F as false, and then for f[i]: f[i] is false because the sum of no elements is equal to 0; For f[nums]: f[nums] is true because the value of the element with subscript 0 is nums.

Spatial optimization of method 1:

```class Solution {
public:
bool canPartition(vector<int>& nums) {
int n = nums.size();
if (n == 1)     //There is only one element, which must not be separated
{
return false;
}
int sum = 0;
int maxnum = INT_MIN;
for (int i = 0; i < n; i++)
{
sum += nums[i];
maxnum = max(maxnum, nums[i]);
}
if (sum % 2 != 0 || maxnum > sum / 2)   //If the sum of elements in the array is odd, it must not be split; If there is an element greater than half of the sum of elements, it must not be split
{
return false;
}
vector<int> f(sum / 2 + 1, false);
//f[j] indicates whether the sum of some elements is equal to j for elements with subscript 0 - i. If yes, it is true; otherwise, it is false

f[nums] = true; //Initializes an element with a subscript of 0 whose value is equal to nums

for (int i = 1; i < n; i++)
{
for (int j = sum / 2; j >= nums[i]; j--)
{
if (j == nums[i])
{
f[j] = true;
//In special cases, f[i][j] is also true when num [i] is exactly equal to j
}
else if (j > nums[i])
{
f[j] = f[j] || f[j - nums[i]];
//The former means not taking num [i], and the latter means taking num [i]
}
}
}
return f[sum / 2];
}
};```

Like the optimization of 01 knapsack problem, changing two-dimensional to one-dimensional, it should also be noted that when traversing, the knapsack should be traversed from large to small. The reason is that when using two-dimensional vector, the value of f[i][j] during traversal depends on the value of [i-1] layer, and the value of [i-1] layer will not change; However, when using a one-dimensional vector, if the knapsack is traversed from small to large, the value of F [j-num [i]] may have been overwritten, resulting in an error, so it should be traversed from large to small instead.

Tags: leetcode

Posted on Mon, 06 Sep 2021 23:04:30 -0400 by helpmeplease1234