leetcode698. 划分为k个相等的子集
给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。
示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
示例 2:
输入: nums = [1,2,3,4], k = 3
输出: false
提示:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
每个元素的频率在 [1,4] 范围内
回溯算法 + 剪枝
首先了解什么是回溯算法:
解决一个回溯问题,实际上就是一个决策树的遍历过程,站在回溯树的一个节点上,你只需要思考 3 个问题:
- 路径:也就是已经做出的选择。
- 选择列表:也就是你当前可以做的选择。
- 结束条件:也就是到达决策树底层,无法再做选择的条件。
代码框架:
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
关于这道题,我们就是要考虑下,如何构造路径和选择列表,我们要选择的路径就是数组的数字,但结束条件呢,就是选择够k个相等的子集,因此我们把这些都放进回溯代码中,进行判断。直接代码演示:
代码演示:文章来源:https://www.toymoban.com/news/detail-613386.html
class Solution {
int n ,_k,t;
int[]_nums;
public boolean canPartitionKSubsets(int[] nums, int k) {
if(nums.length == 1){
return true;
}
if(k > nums.length){
return false;
}
int sum = 0;
for(int i = 0; i < nums.length;i++){
sum += nums[i];
}
if(sum % k != 0){
return false;
}
Arrays.sort(nums);
_nums = nums;
n = nums.length;
_k = k;
t = sum / k;
return dfs(n - 1,0,0,new boolean[n]);
}
/**
*
* @param index
* @param cur 当前元素和
* @param cnt 已经凑够几个和为t的集合。
* @param vis 标记哪些元素被使用过了。
* @return
*/
boolean dfs(int index,int cur,int cnt,boolean[]vis){
//base case 数量刚好满足,
if (cnt == _k){
return true;
}
//当前选择的数字刚好满足时,进行下一次选择
if (cur == t){
//还是从最后一个元素开始选择,cur 初始化为0,集合数量加1,
return dfs(n - 1,0,cnt + 1,vis);
}
for (int i = index;i >= 0;i--){
//剪枝 元素已经选过了,或者选择大于t 进行下一次选择
if (vis[i] || cur + _nums[i] > t){
continue;
}
//选择中的数字标记下
vis[i] = true;
//进行递归
if (dfs(i - 1,cur + _nums[i],cnt,vis)){
return true;
}
//撤销选择
vis[i] = false;
//剪枝,累加和等于0 直接返回false;
if (cur == 0){
return false;
}
}
return false;
}
}
回溯算法
leetcode93. 复原 IP 地址文章来源地址https://www.toymoban.com/news/detail-613386.html
到了这里,关于leetcode698. 划分为k个相等的子集(java)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!