1. 划分为k个相等的子集
(1)回溯,剪枝,贪心
- 将数组划分为k个组,使得每个组的和均相等。
- 求出数组总和sum,如果sum除以k不为整数,肯定就不满足每个组的和相等,直接return false.
- 拿到sum/k的值target后,target就代表每个组的和需要达到的值(超过或不足都不行)
- 同时,如果数组的最大值>target也无法满足题意,return false.
剪枝:
- 找到k-1个满足题意的组合后,就可以return true了。因为剩下未选的元素的和肯定为数组总和sum-(k-1)*target=target。
- 当组合中的元素之和超过了目标值时,就没必要再往组合中添加元素了,直接回溯。
- 如果某个元素无法使得组合达到目标值,那么跟它值相同的元素也不需要添加了
- 举个例子,数组[1,3,3,3],k=2.可以计算出target=5.【1】——此时组合的和为1,小于目标值5,继续往组合中添加元素。添加第一个3,【1,3】,小于5,继续添加。我们发现随后继续添加两个3都超过了5,回溯到【1,3】这个状态。数组遍历完,依然找不到和为5的组合,继续回溯——【1】。此时,我们发现下一个要添加的元素还是3,但在之前我们已经试过了3无法使得当前组合达到目标值,所以就没必要再添加3了,直接continue.
- 从大到小遍历,这有点类似贪心的思想
class Solution {
public boolean canPartitionKSubsets(int[] nums, int k) {
int sum=0;
int len = nums.length;
boolean[] used = new boolean[len];
Arrays.sort(nums);
//求数组总和
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
//如果sum除以k不为整数,肯定就不满足每个组的和相等,直接return false.
//不能整除则子集分不出k份,直接false。
if (sum % k != 0)
return false;
//拿到sum/k的值target后,target就代表每个组的和需要达到的值(超过或不足都不行)
int ta