文章目录
- 题目
- 方法一:递归+回溯+去重
题目
本题需要注意的就是去重操作因为nums数组里面的元素可能存在重复:
不重复的版本:【LeetCode-中等题】39. 组合总和 不去重版
方法一:递归+回溯+去重
参考讲解视频—回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II
class Solution {
// 递归+ 回溯 candidates 有重复元素 加入标志数组考虑去重
List<List<Integer>> res = new ArrayList<>();//最终结果集
int len = 0;//数组长度
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);//对数组排序
len = candidates.length;
List<Integer> zres = new ArrayList<>();//子结果集
int sum = 0; //初始为0
int[] flag = new int[len];//设置 标志位 去重
int startIndex = 0; //设置遍历开始位置 使得每次只能取自己和自己之后的数组成子结果 避免重复子集
dfsback(candidates,zres,sum,target,startIndex,flag);
return res;
}
public void dfsback(int[]candidates, List<Integer> zres,int sum,int target,int startIndex, int[] flag){
if(sum == target){
res.add(new ArrayList<>(zres));//如果sum == target 收获节点的子集合 再往下遍历肯定大于target 所以直接return
return;
}
if(sum > target) return; //如果sum都大于target 后面就无需遍历了
for(int i = startIndex ; i <len ;i++){//题目说同一个 数字可以 无限制重复被选取 那每次遍历都可以从他自己startIndex开始取到数组尾吧
if(flag[i] == 1) continue;
if(i>0 && candidates[i] == candidates[i-1] && flag[i-1] == 0) continue;
//树层去重 若for循环 后面一个元素和前面一个相同,并且前面一个元素的标志位为0 则执行去重操作,跳过以此元素进行的递归层
sum += candidates[i];
flag[i] = 1;
zres.add(candidates[i]);
dfsback(candidates,zres,sum,target,i,flag);//往下递归 这里的i是为了 往下面递归不能取数组前面 的数,不然会出现重复子集 [2,2,3],[2,3,2],[3,2,2]
sum -= candidates[i];//回溯复原原值
flag[i] = 0;
zres.remove(zres.size()-1);
}
}
}