给定一个整数数组 nums
和一个正整数 k
,找出是否有可能把这个数组分成 k
个非空子集,其总和都相等。
示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4 输出: True 说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
注意:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
思路:
- nums集合的所有元素之和为sum,将nums分成k个非空子集,即每个子集的所有元素和为target = sum / k
- 将nums从小到大排序,假设有k个盒子
- 先取最大的一个数,逐个盒子比较,放到当前盒子内数总和加上该数小于target的盒子中,将这个数从原集合中去掉
- 递归进行前一步,直到原集合没有元素了为止
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
int sum = 0;
for (size_t i = 0; i < nums.size(); ++i)
sum += nums[i];
if (sum % k != 0)
return false;
const int target = sum / k;
sort(nums.begin(), nums.end());
while (!nums.empty() && nums[nums.size() - 1] == target)
{
nums.pop_back();
--k;
}
vector<int> group(k, 0);
return partition(group, nums, target);
}
bool partition(vector<int> groups, vector<int> nums, int target)
{
if (nums.empty())
return true;
int v = nums[nums.size() - 1];
nums.pop_back();
for (size_t i = 0; i < groups.size(); ++i)
{
if (v + groups[i] <= target)
{
groups[i] += v;
if (partition(groups, nums, target))
return true;
groups[i] -= v;
}
if (groups[i] == 0)
break;
}
return false;
}
};