🔥博客主页: 我要成为C++领域大神
🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】
❤️感谢大家点赞👍收藏⭐评论✍️本博客致力于知识分享,与更多的人进行学习交流
给定一个整数数组 nums
和一个正整数 k
,找出是否有可能把这个数组分成 k
个非空子集,其总和都相等。
示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
示例 2:
输入: nums = [1,2,3,4], k = 3
输出: false
提示:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
- 每个元素的频率在
[1,4]
范围内
回溯+剪枝
思路
首先计算数组的所有元素的总和,如果这个总和不能被 k
整除,则无法划分,直接返回 false
。
对数组进行逆序排序,尽可能先处理较大的元素,可以提前不可行的情况。
通过DFS结合回溯,将每个元素分配到某个子集中。通过剪枝操作,避免重复计算无效路径。
从第 0 个元素开始调用 dfs
,并返回结果。
代码实现
class Solution {
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % k)
return false;
sum /= k; // 子集的总和
sort(nums.rbegin(), nums.rend()); // 逆序排序
if (nums[0] > sum)
return false;
vector<int> SubSum(k, 0);
function<bool(int)> dfs = [&](int i) {
if (i == nums.size())
return true;
for (int j = 0; j < k; ++j) {
if (j && SubSum[j] == SubSum[j - 1])
continue; // 剪枝操作
if (nums[i] + SubSum[j] <= sum) {
SubSum[j] += nums[i];
if (dfs(i + 1))
return true;
SubSum[j] -= nums[i];
}
}
return false;
};
return dfs(0);
}
};