链接:https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/solution/-by-xun-ge-v-ij15/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
题目
示例
思路
对于本题,我们可以抽象理解一下,相当于是有 k 个一模一样的桶,有nums个球,每个球为nums[i]的大小,问所有球能不能正好装入桶中,桶大小可以调节,但是数目不能变
- 第一步我们需要将nums个球的总大小求出来,并平均分为k份,确定桶大小
- 如果平均分成 k 份存在小数,那么肯定会分布均匀,因为我们能用的球,大小只有整数,分不出小数
- 第二步将球放入桶中,并用递归将所有放入顺序记录下来
- 第三步,在所有顺序中选择一个可行解即可
其实在上述过程中,我们可以不需要记录所有组合,可以边记录边判断,将当前顺序不可行时,回溯返回上一步
代码
bool reverse(int* nums, int numsSize, int k, int target, int* tmpArr, int index)
{
if (index == numsSize) {//所有元素的枚举完了
for (int i = 0; i < k; i++) {//判断是否每个桶都装满了
if (tmpArr[i] != target) {
return false;
}
}
return true;
}
for (int i = 0; i < k; i++) {//枚举每一个桶
if (tmpArr[i] + nums[index] > target) {//当前桶装不下了。下一个去
continue;//剪枝
}
tmpArr[i] += nums[index];//装了
if (reverse(nums, numsSize, k, target, tmpArr, index + 1)) {
return true;//判断当前桶装了之后,下一个是否还能正常装好
}
tmpArr[i] -= nums[index];//下一个不能,说明这个球不是这个桶的,回溯
//如果第一个球,在第一个桶里面装不了,那么因为所有桶都是一样的,
//其他桶肯定也装不了,提前结束
if (tmpArr[i] == 0) {//再剪枝
break;
}
}
return false;
}
bool canPartitionKSubsets(int* nums, int numsSize, int k){
// 计算每个子集的和
int sum = 0;
for (int i = 0; i < numsSize; i++) {
sum += nums[i];
}
if (sum % k != 0) {
return false;
}
int target = sum / k;
int tmpArr[k];
memset(tmpArr, 0, sizeof(int) * k);
return reverse(nums, numsSize, k, target, tmpArr, 0);
}
作者:xun-ge-v
链接:https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/solution/-by-xun-ge-v-ij15/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。