Java:回溯
这道题不是背包:背包是从里面选,你不知道你选的是谁,也没有办法做标记!
可参考:https://leetcode.cn/problems/partition-to-k-equal-sum-subsets/solutions/1441006/by-lfool-d9o7/
这种解法就是在 各种组合 里面查找满足的解,当组合里面有k个解之后,return true;
class Solution {
boolean[] used;
int avr;
private boolean backtracking(int[] nums, int k, int sum, int start) {
if (k == 0) {
return true; // 找到:立即中断栈!并返回值
}
if (sum == avr) { // 构建下一个集合, return相当于把上一个dfs堆栈给掐掉
return backtracking(nums, k-1, 0, 0); // 可理解为有k个桶,装满一个桶后,再装下一个桶!
}
for (int i = start; i < nums.length; i++) { // used[i]逐渐过滤已使用的数字,用剩下的数字重新回溯看能否构建
if (!used[i] && sum + nums[i] <= avr) { // 并不是所有的used[i]都会回溯掉!满足sum == target后会重新开启一个dfs
used[i] = true;
if (backtracking(nums, k, sum + nums[i], i + 1)) {
return true;
}
used[i] = false;
}
}
return false;
}
public boolean canPartitionKSubsets(int[] nums, int k) {
// 注意nums[i] > 0
int sum = 0, maxNum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
maxNum = Math.max(maxNum, nums[i]);
}
if (sum % k != 0 || maxNum > sum/k) {
return false;
}
used = new boolean[nums.length];
avr= sum / k;
return backtracking(nums, k, 0, 0);
}
}
K叉树:
java:参考 2305. 公平分发饼干
K叉树,树的深度为数组的长度,当数组的数字全部用完之后再check是否满足!
左分支一节节的延伸到左下角,然后再遍历最下面一层,再回到上一层遍历上一层,再继续延伸到最下层遍历。
因此,它每次的遍历都是在遍历最底层,查看整条路径是否有满足的值。
class Solution {
private int avr = 0;
public boolean dfs(int index, int[] bucket, int n, int k, int[] nums){
if (index == n){
for (int i = 0; i < k; i++) {
if (bucket[i] != avr) {
return false;
}
}
return true; // 数组中的值使用完了,check是否满足条件!
}
for (int i = 0; i < k; ++i){ // 有k个桶,nums的值分别进入其中一个桶里面
if(bucket[i] + nums[index] > avr) {
continue;
}
if (i > 0 && bucket[i] == bucket[i - 1]) { // 剪枝!少了超时!
continue;
}
bucket[i] += nums[index]; // 往桶挑选里面放值
if (dfs(index + 1, bucket, n, k, nums)) { // 一直延伸到左下角,然后在最底层一根根分支遍历
return true; // 若没有满足的返回false,若返回true直接一条线return,直接结束
}
bucket[i] -= nums[index]; // 当前桶往下的延伸查找没有符合条件的,从这个桶把值取出来,放到另外一个桶中,再延伸查找
}
return false;
}
public boolean canPartitionKSubsets(int[] nums, int k) {
// 注意nums[i] > 0
int sum = 0, maxNum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
maxNum = Math.max(maxNum, nums[i]);
}
if (sum % k != 0 || maxNum > sum/k) {
return false;
}
avr = sum / k;
return dfs(0, new int[k], nums.length, k, nums);
}
}