LeetCode39 组合总和
给定一个无重复元素的数组 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]
]
解题思路:
这个题目使用深度优先搜索+回溯的方法来进行。回溯算法的基本通用解法是使用树形图来解决,画图的过程就是代码生成的过程。另外,做过题目很多的程序员应该发现了一个规律,就是回溯的过程中,在回溯这步代码的前后是对称的,这一点很重要。
注意题目中的剪枝条件,请注意题目要求数字可以重复使用,但是结果集不可以重复。
class Solution{
public List<List<Integer>> combinationSum(int[] candiates, int target){
//定义最终的结果集
List<List<Integer>> resultList=new ArrayList<>();
//定义保存中间的结果集
List<Integer> result=new ArrayList<>();
//将原数组进行排序,这样在生成回溯树的时候不会出现重复的元素。因为数组中的元素是从小到大的排列,遍历的时候后面的元素不会比前面的元素小
Arrays.sort(candiates);
//调用递归的回溯函数
dfs(candiates, resultList, result, 0, target);
return resultList;
}
private void dfs(int[] candiates, List<List<Integer>> resultList, List<Integer> result, int start, int target){
//不符合条件的剪枝
if(target<0){
return;
}
//符合条件的加入结果集
else if(target==0){
//最终的结果集里面保存的是一个个不一样的集合,所以每次加入的都是更新的ArrayList
resultList.add(new ArrayList<>(result));
}
else{
for(int i=start;i<candiates.length;i++){
result.add(candiates[i]);
//下面这步就是开始递归了,注意它的上面一行和下面一行的区别
//【关键】因为元素可以重复使用,这里递归传递下去的是 i 而不是 i + 1
dfs(candiates, resultList, result, i, target-candiates[i]);
//回溯,注意看,和前面是不是很对称
result.remove(result.size()-1);
}
}
}
}