主要用到了深度优先的搜索思想。先将题意进行转化,k个相等的子集也就是说这k个子集的和为sum,且每个子集的和为sum/k。
题目和之前的LeetCode416 分割等和子集的思想一致,也可以转换成背包问题,包的容量为sum/k。不过这次不是只找到一组数来装这一个包,而是找到多个包,这种解法可以找到正确答案,但是代码会很长,不推荐。直接用深度优先的思想做代码量就很简单了。代码如下:
class Solution {
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
if(k==1){//数组本身就是它的一个子集
return true;
}
if(k>nums.size()){ //不可能构成k个子集
return false;
}
int sum=accumulate(nums.begin(),nums.end(),0);
if(sum%k){
return false;
}
int n=nums.size(),target=sum/k,curSum=0;
vector<int> used(n,0);
return ifSubsets(nums,0,0,target,curSum,k,used);
}
bool ifSubsets(vector<int>& nums, int start,int n,int target,int curSum,int k,vector<int>& used)
{// start表示搜索的起点,n为当前已经搜索过的数字数目,curSum为当前的累加和,target,k,used和定义一致
if(curSum>target){return false;}
if(k==0&&n==nums.size()){return true;}
if(curSum==target){ //已经存在一个集合
return ifSubsets(nums,0,n,target,0,k-1,used); //继续从第一个数字开始搜索,start变为0,当前和变为0
}
for(int i=start;i<nums.size();i++)
{//curSum<target
if(used[i]==0)//还没有使用过
{
used[i]=1; //标识
if(ifSubsets(nums,i+1,n+1,target,curSum+nums[i],k,used)){ //还是给第k个子集找值,所以k不变;要把i处的值加上,并从他的下一个位置搜索
return true;
}
used[i]=0; //说明上述子集中没有用到i,所以恢复状态等待下次使用
}
}
return false;
}
};