方法一 回溯法(未剪枝)
就是向前列举所有情况,每个值都有直接跳过和添加两个选择,得到一个解或者走不通的时候就回溯。
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> combine = new ArrayList<>();
backtrack(candidates, target, res, combine, 0);
return res;
}
// target:求和数 res:最终结果 combine:已经组合的数 index:当前下标
public void backtrack(int[] candidates, int target, List<List<Integer>> res, List<Integer> combine, int index){
if(index == candidates.length) return;
if(target == 0){
res.add(new ArrayList<Integer>(combine));
return;
}
backtrack(candidates, target, res, combine, index + 1);
if(target - candidates[index] >= 0){
combine.add(candidates[index]);
backtrack(candidates, target - candidates[index], res, combine, index);
combine.remove(combine.size() - 1);
}
}
}
方法二 回溯法(剪枝)
对 candidates 排序,以减少回溯次数。
class Solution {
private List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<Integer> combine = new ArrayList<>();
Arrays.sort(candidates);
backtrack(candidates, target, combine, 0, 0);
return res;
}
public void backtrack(int[] candidates, int target, List<Integer> combine, int index, int sum){
if(index == candidates.length) return;
if(target == sum){
res.add(new ArrayList<Integer>(combine));
return;
}
for(int i = index; i < candidates.length; i++){
int rs = candidates[i] + sum;
if(rs <= target){
combine.add(candidates[i]);
backtrack(candidates, target, combine, i, rs);
combine.remove(combine.size() - 1);
}else{
break;
}
}
}
}