698. Partition to K Equal Sum Subsets
Given an array of integers nums
and a positive integer k
, find whether it’s possible to divide this array into k
non-empty subsets whose sums are all equal.
Example 1:
Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: True
Explanation: It’s possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.
Note:
- 1 <= k <= len(nums) <= 16
.
- 0 < nums[i] < 10000
.
题目大意
给出一组序列和一个参数k
,判断这组序列是否能拆分成k
组和相等的序列。
解题思路
- 一个简单的检测,即序列的总和是否能被
k
整除。如果不能,直接得出false
的结论;如果能则进入接下来的检测。 - 获得该序列的平均值
avg
,所有的子序列之和必须等于这个平均值。 - 创建一个
valid
数组记录每一个位置的分配情况。 - 对数组进行排序,然后从大打小遍历数组:
1) 如果当前数值大于平均值avg
,则直接得出false
的结论。
2) 如果当前位置已被分配到子序列,则跳过该值。
3) 使用定义的函数determineNumOfGroup
递归求解该值能否被分配。输入平均值avg
和当前位置。 - 关于函数
determineNumOfGroup
,以传入的起始位置开始,从大到小遍历序列:
1) 如果该位置已经被分配或者当前数值大于平均值avg
,则跳过。
2) 如果当前数值等于平均值avg
,则将该位置标记为已被分配,返回1。
3) 如果当前数值小于平均值avg
,递归调用函数determineNumOfGroup
,以avg
-当前数值为之后寻找的新的avg
,并传入下一个位置作为起始位置。如果返回为1,则将当前位置标记为已被分配,返回1。
4) 如果遍历一遍之后,还是不存在数值满足上述条件,则返回0.
代码实现
class Solution {
public:
int determineNumOfGroup(vector<int>& nums, vector<bool>& valid, const int& avg, const int& begin) {
for (int i = begin; i >= 0; i--) {
if (valid[i] == true || nums[i] > avg) continue;
else if (nums[i] == avg) {
valid[i] = true;
return 1;
} else {
if (determineNumOfGroup(nums, valid, avg-nums[i], i-1) == 1) {
valid[i] = true;
return 1;
}
}
}
return 0;
}
bool canPartitionKSubsets(vector<int>& nums, int k) {
int len = nums.size();
int sum = 0;
vector<bool> valid(len, false);
for (int i = 0; i < len; i++) {
sum += nums[i];
if (nums[i] == 0) valid[i] = true;
}
if (sum % k != 0) { return false; }
int avg = sum / k;
sort(nums.begin(), nums.begin()+len);
int numOfGroup = 0;
for (int i = len-1; i >= 0; i--) {
if (nums[i] > avg) return false;
else if (valid[i] == true) continue;
else numOfGroup += determineNumOfGroup(nums, valid, avg, i);
}
for (int i = 0; i < len; i++) {
if (valid[i] == false) return false;
}
return numOfGroup == k;
}
};