class Solution {
// 回溯类问题 : 递归 + 回溯 (一趟递归结束了,递归结束才是重头戏,现在要向上回溯,回溯还没结束)
// 对于有多个解的问题,一条路上的递归结束了,找到了一个解( 最好的方法就是在一趟递归结束以后,创建工作数组的副本,任何操作都对这个副本进行,不要动工作数组本身)。这个时候也不能对工作数组做任何一点改动,即使是排序也不行
// 因为这会使 工作数组内的元素顺序发生改变,从而 “回溯” 的过程中,撤销对结点的操作时发生错乱
Set<List<Integer>> res;
LinkedList<Integer> tem;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
res = new HashSet<>();
tem = new LinkedList<>();
int len = candidates.length;
dfs(candidates, target, tem);
return new ArrayList<>(res);
}
public void dfs(int[] candidates, int target, LinkedList<Integer> tem) {
if (target == 0) {
ArrayList<Integer> tt = new ArrayList<>(tem);
Collections.sort(tt);
res.add(tt);
return;
// 不能用下面的做法,因为对于有多个结果的回溯问题,即使是一条路上的递归完成了,因为回溯还没完成。
// 本题错误的地方: 是递归 结束了 ,回溯还没结束, 我就把工作数组给排序了,这样就改变了工作数组内元素的顺序,这样在逐步向上回溯的过程中就会发生错乱
// System.out.println("排序前tem ="+tem);
// Collections.sort(tem);
// System.out.println("排序后tem ="+tem);
// res.add(new ArrayList<>(tem));
// return;
}
if (target < 0) { // 剪枝,不可能产生正确结果的路就直接返回,不用走到路的尽头再返回
return;
}
for (int i = 0; i < candidates.length; i++) {
if (target >= 0) {
tem.add(candidates[i]);
dfs(candidates, target - candidates[i], tem);
tem.removeLast();
}
}
return;
}
}
第二种方法:
利用 begin 在 for循环 中去重,重点体会begin的去重作用:
代码如下;(begin使得当前结点可以重复选取,并且不会回头往前面选取,所有元素要想被多次选取,就只有一次机会,错过了就没了)
加入begin之前: [2,3,2] 和 [2,2,3] 是重复的答案,必须删除【2,3,2】
加入begin之后:成功去重
代码如下:
class Solution { Set<List<Integer>> res; LinkedList<Integer> tem; public List<List<Integer>> combinationSum(int[] candidates, int target) { res = new HashSet<>(); tem = new LinkedList<>(); int len = candidates.length; dfs(candidates, target,0, tem); //begin初始为0 return new ArrayList<>(res); } public void dfs(int[] candidates, int target, int begin,LinkedList<Integer> tem) { if (target == 0) { ArrayList<Integer> tt = new ArrayList<>(tem); //Collections.sort(tt); res.add(tt); return; } if (target < 0) { // 剪枝,不可能产生正确结果的路就直接返回,不用走到路的尽头再返回 return; } for (int i = begin; i < candidates.length; i++) { if (target >= 0) { tem.add(candidates[i]); dfs(candidates, target - candidates[i], i,tem); // begin为i tem.removeLast(); } } // return; 不需要 } }