leetcode 416. Partitioning equal sum subset medium
Title Description:
Given a non-empty array containing only positive integers. Can this group be divided into two subsets so that the elements of the two subsets are equal?
Be careful:
Elements in each array will not exceed 100
The size of the array will not exceed 200
Example 1:
Input: [1, 5, 11, 5]
Output: true
Interpretation: Arrays can be divided into [1, 5, 5] and [11].
Example 2:
Input: [1, 2, 3, 5]
Output: false
Interpretation: Arrays cannot be divided into two elements and an equal subset.
Ideas for solving problems:
Because it requires dividing into two equal subsets, and all the elements are positive (in fact, negative numbers, as long as the number of alternatives is greater than or equal to 2), we only need to have a solution to make the capacity of the array half and Ok.
Capacity 01 knapsack, to find whether there is a capacity of exactly half the sum of the array, so when initializing, note that except dp [0] is true, the other is false, ojkb
Code:
// class Solution { public: bool canPartition(vector<int>& nums) { //01 knapsack. Seek if there is a solution with exactly half the capacity of the array. if(nums.size()<2) return false; int sum=0; for(int i:nums) sum += i; if(sum & 1) // Odd impossible return false; sum >>= 1; vector<bool> dp(1+sum,false); dp[0]=true; for(int i:nums){ if(dp[sum]==true) return true; // You can speed it up in the middle. for(int j=sum;j>=i;--j) //01 backpack traversal from large to small dp[j]=dp[j] || dp[j-i]; } return dp[sum]; } };
leetcode 698. Divided into k equal subsets medium
Title Description:
Given an integer array nums and a positive integer k, find out if it is possible to divide the array into k non-empty subsets, the sum of which is equal.
Example 1:
Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: True
Explanation: It is possible to divide it into four subsets (5), (1,4), (2,3), (2,3) equal to the sum.
Be careful:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
Ideas for solving problems:
With backtracking, you can't do it with dp (and that's for collections, so you have to start the variable, because for arrays [1, 2, 3], [1, 2] is the same as [2, 1].
We can do it recursively. First, we can find the sum of all the numbers in the array. First, we can judge whether sum can divide k, and if it can't divide, we can return false directly. Then we need a visited array to record which arrays have been selected, and then call the recursive function. Our goal is to set K subsets of the group, and the sum of each subset is target = sum/k. We also need the variable start, which means to start looking up from somewhere in the array, curSum is the sum of the current subsets. In the recursive function, if k=1, it means that only one subset of the group is needed at this time, then the current one is to return true directly. If curSum equals target, then we call recursion again, and then k-1 is passed in. Start and curSum are reset to zero, because we have found a subset of target and we need to start looking for the next one. Otherwise, the array is traversed from start, and if the current number has been accessed, it is skipped directly. Otherwise, it is marked as accessed. Then the recursive function is called, K remains unchanged, because the current subset is still accumulating, start passes in i+1, curSum passes in curSum+nums[i], because to accumulate the current number, if the recursive function returns true, it returns true directly. Otherwise, reset the current number to an unavailable state and continue traversing
We can also optimize the above solutions, such as sorting arrays in order from large to small, and then in recursive functions, we can directly judge that if curSum is larger than target, we can directly return false, because the title is defined as positive numbers, and we also sort arrays, followed by the number. Words can only be larger, and this pruning operation greatly improves the speed of operation.
Code:
// class Solution { public: bool canPartitionKSubsets(vector<int>& nums, int k) { int sum = accumulate(nums.begin(), nums.end(), 0); if (sum % k != 0) return false; vector<bool> visited(nums.size(), false); return helper(nums, k, sum / k, 0, 0, visited); } bool helper(vector<int>& nums, int k, int target, int start, int curSum, vector<bool>& visited) { if (k == 1) return true; if (curSum == target) return helper(nums, k - 1, target, 0, 0, visited); for (int i = start; i < nums.size(); ++i) { if (visited[i]) continue; visited[i] = true; if (helper(nums, k, target, i+1, curSum + nums[i], visited)) return true; visited[i] = false; } return false; } }; // class Solution { public: bool canPartitionKSubsets(vector<int>& nums, int k) { int sum = accumulate(nums.begin(), nums.end(), 0); if (sum % k != 0) return false; sort(nums.begin(), nums.end(), greater<int>()); vector<bool> visited(nums.size(), false); return helper(nums, k, sum / k, 0, 0, visited); } bool helper(vector<int>& nums, int k, int target, int start, int curSum, vector<bool>& visited) { if (k == 1) return true; if (curSum > target) return false; if (curSum == target) return helper(nums, k - 1, target, 0, 0, visited); for (int i = start; i < nums.size(); ++i) { if (visited[i]) continue; visited[i] = true; if (helper(nums, k, target, i + 1, curSum + nums[i], visited)) return true; visited[i] = false; } return false; } };