题目:
分析:数字组合的问题,组合出符合目标值的所有情况,所有数字都可以重复使用,很容易想到使用回溯(深度遍历)来做解决。以第一个示例为例,从2开始,减去2后目标变成5,那么就要求出能组合成5的组合,加上一开始的2就组成以2开头的所有解;如果从3开始,目标变成4,接下来就要求出能组合成4的组合;以此类推,画图画出一棵树会好理解很多。
要注意的点:
1.先对可取值进行排序,升序排列,这样可以方便判断解的组合是否重复且方便剪枝
2…停止回溯的条件:目标值变成0,即已经找到一种解法,添加到结果,返回。
3.剪枝。如果当前值大于目标值,那么往后的值都不用考虑了,因为后面的值更大
4.下一次考虑求解的起始值,因为每个值都可重复使用,所以下一次考虑求解的起始值跟上一个相同,再考虑后面的值(再之前的值不考虑了,因为在之前的值比上一个小,由于是深度比遍历的做法,所以之前一定考虑过了)
代码:
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
dfs(candidates, target, 0, path, result);
return result;
}
public void dfs(int[] candidates, int target, int begin, List<Integer> path, List<List<Integer>> result){
if(target == 0){
//这里要new一个,因为path是引用,如果直接添加引用,后面引用变化了,里面的值也会变化
result.add(new ArrayList<>(path));
return;
}
for(int i = begin; i < candidates.length; i++){
//剪枝
if(target - candidates[i] < 0){
break;
}
path.add(candidates[i]);
dfs(candidates, target-candidates[i], i, path, result);
path.remove(path.size()-1);
}
}
}