题目描述:
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.
给定一个整数数组 nums
和一个正整数 k
,找出是否有可能把这个数组分成 k
个非空子集,其总和都相等。
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.
示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
Note:
1 <= k <= len(nums) <= 16
.0 < nums[i] < 10000
.
思路:
该题目可以用深度优先搜索算法。
先计算出子序列的目标序列和target,即用数组nums的总和除以k,如果余数不为0,说明nums不可能被分成k个总和相等的非空子集,返回false。
否则,从nums数组的第一个元素开始,寻找加和等于target的元素的组合,组合中的元素被标记,不参与下一轮递归的选取;当选出一组子序列后,进入下一轮递归,重新从nums数组的第一个元素开始,从未被标记的元素中继续寻找符合要求的子序列。
如果本轮递归无法找到目标和为target的子序列,原因有两个,一是nums数组本来就无法满意题意,二是应该构成本轮递归子序列的元素已经在之前的某一轮递归中被使用,因此需要回溯重新构造之前的子序列。
直到所有的元素被标记,并且找到了k个加和等于target子序列,才返回true,其余的情况都返回false。
实现(C++):
class Solution {
public:
bool canPartitionKSubsets(vector<int>& nums, int k) {
if(k==1)
return true;
if(k>nums.size())
return false;
int sum=0;
for(int i=0; i<nums.size(); i++)
sum+=nums[i];
if(sum%k)
return false;
int target=sum/k; //子序列和的目标和
int visited[nums.size()]; //访问标记数组
memset(visited, 0, sizeof(int)*nums.size()); //visited数组的元素都初始化为0
return dfs(nums,0,0,target,0,k,visited); //深度优先搜索,返回判断结果
}
public:
bool dfs(vector<int>& nums, int start, int n, int target, int sub_sum, int k, int visited[])
{
//nums nums数组
//start 本次深搜的起始位置
//n 记录被访问元素的个数
//target 子序列的目标和
//sub_sum 当前的子序列和
//k 当前还差k个目标和为target的子序列未被找到
//visited 访问标记数组
if(k==0&&n==nums.size())
//如果已经凑齐所有目标和为target的子序列,并且nums数组的所有元素都被标记,返回true
return true;
if(sub_sum==target)
//如果找到一个和为target的子序列,则当前还差k-1个目标和为target的子序列未被找到,需要重新从nums数组的第一个元素开始,继续从未被标记的元素中寻找下一个目标和为target子序列
return dfs(nums,0,n,target,0,k-1,visited);
for(int i=start;i<nums.size();i++)
{
if(visited[i]==0)
{
if(sub_sum+nums[i]<=target){
visited[i]=1;
n=n+1;
//下一次递归从当前元素的下一个元素开始搜索,即start=i+1
return dfs(nums,i+1,n,target,sub_sum+nums[i],k,visited);
n=n-1; //回溯
visited[i]=0;
}
}
}
return false;
}
};