题目
给定一个整数数组 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]
范围内
解题
方法一:DFS 回溯 排序 剪枝
思路
这题是:【DFS, 回溯】火柴拼正方形 的升级版,只是 换成了 ,代码基本一样。
剪枝:
if (i > 0 && groups[i] == groups[i - 1]) continue;
这个剪枝直接从 TLE 剪到了 1ms( i be like “wtf???”
代码
class Solution {
int[] nums, groups;
int k, groupSum;
public boolean canPartitionKSubsets(int[] _nums, int _k) {
nums = _nums;
k = _k;
groups = new int[k];
int tot = 0;
for (int num : nums) tot += num;
if (tot % k != 0) return false;
groupSum = tot / k;
Arrays.sort(nums);
return dfs(nums.length - 1);
}
boolean dfs(int idx) {
if (idx == -1) return true;
int curr = nums[idx];
for (int i = 0; i < k; ++i) {
if (groups[i] + curr > groupSum ||
i > 0 && groups[i] == groups[i - 1]) continue;
groups[i] += curr;
if (dfs(idx - 1)) return true;
groups[i] -= curr;
}
return false;
}
}
class Solution {
vector<int> nums, groups;
int k, group_sum, n;
public:
bool canPartitionKSubsets(vector<int>& _nums, int _k) {
nums = _nums;
k = _k;
groups.resize(k, 0);
int tot = accumulate(nums.begin(), nums.end(), 0);
if (tot % k) return false;
group_sum = tot / k;
sort(nums.begin(), nums.end(), greater<>());
n = nums.size();
return dfs(0);
}
bool dfs(int idx) {
if (idx == n) return true;
int& curr = nums[idx];
for (int i = 0; i < k; ++i) {
if (groups[i] + curr > group_sum ||
i > 0 && groups[i] == groups[i - 1]) continue;
groups[i] += curr;
if (dfs(idx + 1)) return true;
groups[i] -= curr;
}
return false;
}
};
评论区