题目
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target
的组合。candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。 解集不能包含重复的组合。 示例 1: 输入:candidates = [2,3,6,7],
target = 7, 所求解集为: [ [7], [2,2,3] ]示例 2: 输入:candidates = [2,3,5], target = 8, 所求解集为: [ [2,2,2,2],
[2,3,3], [3,5] ]
思路
注意:本题可以无限制重复取数字
回溯三部曲:
-
回溯函数参数和返回值:定义两个全局变量,二维数组
result
存放结果集,数组path
存放单个结果,参数为题目给出的集合candidates
和目标值target
,另外还需要startIndex
来控制for
循环的起始位置如果是一个集合来求组合,就需要
startIndex
,比如组合、组合总和等等,如果是多个集合求组合,多个集合之间不会相互影响,就不用startIndex
,比如电话号码的字母组合,每个数字有自己对应的集合 -
递归终止条件:一共两种情况
if(sum > target){
return;
}
if(sum == target){//sum等于target的时候,需要收集结果
result.add(path);
return;
}
- 单层搜索的逻辑:单层
for
循环从startIndex
开始,搜索集合
剪枝优化:
对于sum
大于target
的情况,其实还是进入了下一层递归判断,在递归判断结束后才判断sum>target
是否满足,剪枝可以将下一层递归判断去掉,对总集合进行排序后,如果已经知道下一层的sum
会大于target
的话,就没有必要进入下一层递归了。
java代码如下:
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
dfs(candidates,target,0 ,0);
return result;
}
public void dfs(int[] candidates, int target, int sum ,int startIdx){
if(sum == target){
result.add(new ArrayList<>(path));
return;
}
for(int i = startIdx; i < candidates.length; i++){
if(sum + candidates[i] > target){
break;
}
path.add(candidates[i]);
dfs(candidates,target,sum + candidates[i],i);//因为candidates 中的数字可以无限制重复被选取,所以这里i不用i++
path.remove(path.size() - 1);
}
}
}