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.
Basic Idea:
这是 416. Partition Equal Subset Sum 的follow up,方法也和之前的题目类似。
起初我的想法是先创建第一个subset,然后第二个。。以此类推,但是这样不容易实现,逻辑太复杂。最后的做法是创建一个长度为 k 的数组表示每个subset的sum值,然后进行dfs,每层考虑一个index的数字会被放入哪个subset,共有len(nums)层。时间复杂度为O(k^len(nums))。
class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
int sum = 0;
for (int num : nums) sum += num;
if (sum % k != 0) return false; // 如果sum/k除不尽,说明不存在这样的partition
sum /= k;
for (int num : nums) if (num > sum) return false;
int[] setList = new int[k];
return helper(nums, setList, 0, sum);
}
private boolean helper(int[] nums, int[] setList, int pos, int targetSum) {
if (pos == nums.length) return true;
Set<Integer> currSumSet = new HashSet<>();
for (int i = 0; i < setList.length; ++i) {
int currSum = setList[i];
if (! currSumSet.add(currSum)) continue;
if (nums[pos] + currSum <= targetSum) {
setList[i] += nums[pos];
if (helper(nums, setList, pos + 1, targetSum)) return true;
setList[i] -= nums[pos];
}
}
return false;
}
}
class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
if (nums.length < k) return false;
int sum = 0;
for (int num : nums) sum += num;
if (sum % k != 0) return false;
int target = sum / k;
for (int num : nums) if (num > target) return false;
return dfs(new int[k], nums, 0, target);
}
private boolean dfs(int[] sets, int[] nums, int pos, int target) {
if (pos == nums.length) return true;
int num = nums[pos];
boolean ret = false;
Set<Integer> set = new HashSet<>();
for (int i = 0; i < sets.length; ++i) {
if (!set.add(sets[i])) continue;
if (sets[i] + num <= target) {
sets[i] += num;
ret |= dfs(sets, nums, pos + 1, target);
sets[i] -= num;
}
}
return ret;
}
}