题目来源:https://leetcode.com/problems/partition-to-k-equal-sum-subsets/
问题描述
698. Partition to K Equal Sum Subsets
Medium
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.
------------------------------------------------------------
题意
给出一个数组nums和一个整数k, 求nums能否被分成k个子集,使得子集中的元素之和相等。
------------------------------------------------------------
思路
深搜剪枝。标答里有好几个剪枝技巧,非常难想到:
1. 最重要的剪枝:由于k个子集是无序的,因此line 29~31的键值可以避免一些如下情况带来的重复,其中一种组合在k个子集进行了全排列。
2. 不算剪枝的加速技巧(次重要):判断是否为true时,如果cur指针移动到0之前,那么就可以返回true了,无需比较targets数组的每一项是否等于target. 这是因为line 22已经限定了targets的值永远 <= target,一旦所有nums数组中的数用完,说明targets各项必须等于target
3. 对nums进行排序,过滤掉nums中大数超过target或等于target的情况,并从大到小尝试放入targets,提前过滤掉nums中元素大小不均衡的情形
------------------------------------------------------------
代码
class Solution {
// for debug
private void printArray(int[] arr) {
for (int item: arr) {
System.out.print(item + ", ");
}
System.out.println();
}
/**
* nums: original array
* cur: current position of pointer in original array
* targets: sum array of {@code k} subsets
* target: target sum of each subset
*/
private boolean dfs(int[] nums, int cur, int[] targets, int target) {
int n = nums.length, k = targets.length;
if (cur < 0) {
return true;
}
for (int j=0; j<k; ++j) {
if (targets[j] + nums[cur] <= target) {
targets[j] += nums[cur];
if (dfs(nums, cur-1, targets, target)) {
return true;
}
targets[j] -= nums[cur];
}
if (targets[j] == 0) {
break;
}
}
return false;
}
public boolean canPartitionKSubsets(int[] nums, int k) {
int sum = 0, n = nums.length;
if (n < k || k == 0) {
return false;
}
for (int num: nums) {
sum += num;
}
if (sum % k != 0) {
return false;
}
int target = sum / k;
Arrays.sort(nums);
if (nums[n-1] > target) {
return false;
}
while (nums[--n] == target) {
--k;
};
int[] targets = new int[k];
return dfs(nums, n, targets, target);
}
}