package com.david.leetcode;
import java.util.ArrayList;
import java.util.List;
public class T39 {
/**
思路
直接上回溯算法框架。解决一个回溯问题,实际上就是一个决策树的遍历过程。你只需要思考 3 个问题:
1、路径:也就是已经做出的选择。
2、选择列表:也就是你当前可以做的选择。
3、结束条件:也就是到达决策树底层,无法再做选择的条件。
代码方面,回溯算法的框架:
result = []
void backtrack(路径, 选择列表(int start,int end(可选),object[]resource),object 用于判断条件是否成立的对象 ):
if 满足结束条件:
result.add(路径)
return;
if(不满足条件的的第一种情况):
...
if(不满足条件的第N种情况):
.....
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)//注意去重
撤销选择
其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。
*/
class Solution {
List<List<Integer>> res = new ArrayList<>();
private void generateAll(int[]candidates,int start,int target,int sum,List<Integer> root){
//注意这里要重新对象化root,不能直接add(root)!(为什么?)
if(sum==target) {res.add(new ArrayList<Integer>(root));return;}
if(sum>target){return ;}
for(int i=start;i<candidates.length;i++){
//执行本次选择
sum+=candidates[i];
root.add(candidates[i]);
/*回溯(此处原start索引指向i而不是指向start是为了去重)能实现去重的原因是我们是从左往右遍历穷举所有可能,所以此时如果将start索引重新指向start,会出现现在的满足条件的新组合与已经遍历过的满足条件的旧组合重复的情况(即这种情况再之前就已经遍历到了,而将start指向i就可以避免这种情况因为candidates[]是不含重复元素的)如:[2,2,3]与[3,2,2]且[2,2,3]一定会先于[3,2,2]遍历到,所以[3,2,2]就是重复的,所以要使start指向i而不是start
如果从头开始组合就
*/
generateAll(candidates,i,target,sum,root);
//撤销本次选择(撤销本次选择是为了消除本次选择的影响,不影响下一轮的结果)
sum-=candidates[i];
root.remove(root.size()-1);
}
}
public List<List<Integer>> combinationSum(int[] candidates, int target) {
int n = candidates.length;
if(n<=0) return res;
List<Integer> root = new ArrayList<>();
generateAll(candidates,0,target,0,root);
return res;
}
}
}
leetcode T39
最新推荐文章于 2024-09-19 19:39:54 发布