冲冲冲,做完今天的题,后面开始重新看juc包源码!
leetcode 40. 组合总和2
思路
- 还是用回溯,但是用set去重的话超时,
- 接下来看了下大佬的思路,如果我们对数组排序:为1,1,7;target=8,我们新增一个start值,记录是从哪个数组下标开始的,
关键过程:
- start=0,i=start=0,此时stack选择了1,sum=1<8;
- 递归进入,start=1,i=1,此时stack1,1,sum=2<8
- 递归进入,start=2,i=2,此时stack=1,1,7,sum=9>8, 于是开始回溯
- 回溯到上一层 sum - 7 = 2, stack退出7,变成1,1
- 继续for循环,i++=2,此时stack1,7,sum=8,
- 加入结果集,RETURN
- 回溯到上一层 sum - 1 = 1, stack=1,此时i到len-1了,回溯到上一层
- 递归进入,start=1,i=1,此时stack1,1,sum=2<8
- 回溯到第一层, 关键来了!start=0,stack为null,i此时++了,应该是1,但是数组1=数组0,如果我们选择1,那么就可能存在重复接了!!
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int sum = 0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
// 先进行排序
Arrays.sort(candidates);
backtrack(0, candidates, target);
return res;
}
public void backtrack(int start, int[] candidates, int target) {
if (sum == target) {
res.add(new ArrayList<>(path));
return;
}
// 剪枝操作
for (int i = start; i < candidates.length && sum + candidates[i] <= target; ++i) {
// 去重
if (i > start && candidates[i] == candidates[i - 1]) continue;
path.add(candidates[i]);
sum += candidates[i];
backtrack(i+1, candidates, target);
sum -= candidates[i];
path.remove(path.size() - 1);
}
}
}
leetcode 39. 组合总和
思路
- 很明显要用到回溯算法(循环+递归),但是难点在如何去重?
- 第一感觉用Set,这种也好写,就是很慢,不过这道题能ac出来
class Solution {
// huisu,set去重,92ms,超过5%
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<Integer> stack = new ArrayList<>();
Set<List<Integer>> result = new HashSet<>();
int sum = 0;
huisu(candidates, target, stack, result, 0);
Arrays.sort(candidates);
List<List<Integer>> result2 = new ArrayList<>();
for (List<Integer> list : result){
result2.add(list);
}
return result2;
}
private void huisu(int[] candidates, int target, List<Integer> stack, Set<List<Integer>> result, int sum) {
if (sum == target){
List<Integer> arr = new ArrayList<>(stack);
Collections.sort(arr);
result.add(arr);
return;}
if (sum > target){return;}
for (int i =0;i<candidates.length;i++){
stack.add(candidates[i]);
sum += candidates[i];
huisu(candidates,target,stack,result,sum);
sum -= candidates[i];
stack.remove(stack.size()-1);
}
}
}
- 参考上面一题的去重思路,这道题因为是可以重复使用数字,所以我们start不主动+1
// huisu
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<Integer> stack = new ArrayList<>();
List<List<Integer>> result = new ArrayList<>();
int sum = 0;
Arrays.sort(candidates);
huisu(candidates, target, stack, result,0, 0);
return result;
}
private void huisu(int[] candidates, int target, List<Integer> stack, List<List<Integer>> result,int start, int sum) {
if (sum == target){
List<Integer> arr = new ArrayList<>(stack);
result.add(arr);
return;}
if (sum > target){return;}
for (int i =start;i<candidates.length;i++){
stack.add(candidates[i]);
sum += candidates[i];
huisu(candidates,target,stack,result,i,sum);
sum -= candidates[i];
stack.remove(stack.size()-1);
}
}