1.题解 回溯 直接100%
class Solution {public: bool canPartitionKSubsets(vector<int>& nums, int k) { int ans = accumulate(nums.begin(),nums.end(),0); if(ans%k !=0)return false; //排除不可能的结果 int target = ans/k; sort(nums.begin(),nums.end(),greater<int>()); //从大到小的排序,减少循环 if(*max_element(nums.begin(),nums.end())>target) return false;//如果有大于target的,肯定会报错。 vector<bool> used(nums.size(),false); vector<int> bucket(k,0); return dfs(bucket,used,0,0,target,nums); } bool dfs(vector<int> &bucket,vector<bool> &used,int b,int start,int target,vector<int>& nums) { //start为当前数字位置,b为当前的桶 if(b == bucket.size()) return true; if(bucket[b] == target) return dfs(bucket,used,b+1,0,target,nums); for(int i=start;i<nums.size();i++) { if(bucket[b] + nums[i] > target) continue; if(used[i]) continue; used[i] = true; bucket[b] += nums[i]; if(dfs(bucket,used,b,i+1,target,nums)) return true; used[i] = false; bucket[b] -= nums[i]; if(bucket[b] == 0) return false; //如果处理之后又bucket还为0,直接剪枝 } return false; }};
2.题解 dp
class Solution { int dp[(1 << 16) + 2];public: bool canPartitionKSubsets(vector<int>& nums, int k) { int n = nums.size(); fill(dp,dp+(1<<16)+2,-1); int sum = 0; for(int i = 0;i < n;i++){ sum += nums[i]; } if (sum % k != 0) return false; int target = sum / k; dp[0] = 0; for(int mask = 0; mask < (1 << n);mask++){ if(dp[mask] == -1) continue; for(int i = 0;i < n;i++){ if(!(mask & (1 << i)) && dp[mask] + nums[i] <= target) dp[mask | (1 << i)] = (dp[mask] + nums[i]) % target; //能否刚好为0 } } return dp[(1 << n)-1] == 0; // 所有书取到 } };