给定一个整数数组 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
//======================================================================
int left = 0; //剩余期望之和
bool findSubSet(int * nums, int numsSize, int target, int * visit)
{
//如果期望值为0,则说明已经找齐元素,返回true
if (0 == target)
{
return true;
}
//剩余期望值为left
left = target;
//同步遍历数组和访问标记
for (int i = 0; i < numsSize; i++)
{
//如果访问标记为1,则已经访问过,直接跳过
if (1 == visit[i])
{
continue;
}
//剩余期望值为0,说明已找齐元素,返回true
if (left == 0)
{
return true;
}
//如果剩余期望值小于当前元素值,则跳过
if (left - nums[i] < 0)
{
continue;
}
//如果剩余期望值等于当前元素值,则找齐元素,返回true
if (left - nums[i] == 0)
{
visit[i] = 1; //修改元素访问标记
left = 0; //剩余期望值为0
return true;
}
//当前元素访问标记置1
visit[i] = 1;
//继续查找剩余期望值需要的元素,left - nums[i] 为剩余期望值
bool res = findSubSet(nums, numsSize, left - nums[i], visit);
//如果剩余期望值没找到,重置该元素访问标记为0,说明已访问的找个元素组合不合适,需要恢复剩余期望值和访问标记,继续后续的遍历
if (false == res)
{
visit[i] = 0;
left = left+nums[i];
}
//如果剩余期望值找到,则返回true
else
{
left = 0;
return true;
}
}
//如果遍历结束,找不到期望的元素,则返回false
return false;
}
//从大到小排序
int compare(const void * src, const void * dst)
{
int i = *(int *)src;
int j = *(int *)dst;
if (i > j)
{
return -1;
}
if (i == j)
{
return 0;
}
return 1;
}
bool canPartitionKSubsets(int* nums, int numsSize, int k) {
//特殊条件
if (NULL == nums || numsSize<1 || k<1)
{
return false;
}
//计算元素之和
int sum = 0;
for (int i = 0; i < numsSize; i++)
{
sum += nums[i];
}
//如果不划分k个子集,则返回false
if (0 != sum % k)
{
return false;
}
//对数组元素排序,从到到小
qsort(nums, numsSize, sizeof(int), compare);
//构建访问标记数组
//int * visit = (int *)malloc(sizeof(int) * numsSize);
//memset(visit, 0x0, sizeof(int) * numsSize);
int visit[numsSize];
for(int i=0; i<numsSize; ++i)
{
visit[i]=0;
}
//k个子集中每个子集的计算期望和
int target = sum /k;
//因为每个元素大于0,如果出现元素大于期望之和,则返回false
for (int i = 0; i < numsSize; i++)
{
if (nums[i] > target)
{
return false;
}
}
//划分k个子集,划分k次
for (int i = 0; i < k; i++)
{
//如果一次false,则直接返回false
if (false == findSubSet(nums, numsSize, target, visit))
{
return false;
}
}
//k个子集全部划分成功,则返回true
return true;
}