题目
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次
示例 :
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
回溯一般模板
1、会使用深度优先遍历的递归
2、数据是否排序
(1)如果不允许数据重复,要先对数组进行排序,递归的时候,起始节点=当前的index+1,而且
同层相同元素不重复执行
(2)数据允许重复,不用对数组排序,递归的时候,起始节点=当前的index
3、完全递归,把数据恢复到上一个状态,也就是回溯
模板总结
参数说明:
|------------|---------------------------|
| start | 开始的数组下标 |
| candidates | 数组 |
| sum | 达到的条件(这里以数据和为例),具体的按题目要求换 |
| resultList | 所有结果 |
| path | 中间过程,符合要求的一组数据 |
允许数据重复一般模板
public static void dfsNum(int start, int[] candidates, int target, int sum, List<List<Integer>> resultList, List<Integer> path) {
if (结束递归条件) {
return;
}
if (符合要求数据条件) {
resultList.add(new ArrayList<>(path));
return;
}
for (int i = start; i < candidates.length; i++) {
if (剪枝条件) {
break;
}
sum += candidates[i];
path.add(candidates[i]);
dfsNum(i, candidates, target, sum, resultList, path);
//回溯,过程中使用的数据,恢复原值
path.remove(path.size() - 1);
sum -= candidates[i];
}
}
不允许数据重复一般模板
public static void dfsNum(int start, int[] candidates, int target, int sum, List<List<Integer>> resultList,List<Integer> path) {
if (结束递归条件) { return; }
if (符合要求数据条件) {
resultList.add(new ArrayList<>(path));
return;
}
for (int i = start; i < candidates.length; i++) {
//最外层重复数据不重复执行
if (i > start && candidates[i] == candidates[i - 1]) {
continue;
}
if (剪枝条件) {
break;
}
sum += candidates[i];
path.add(candidates[i]);
dfsNum(i + 1, candidates, target, sum, resultList, path);
//回溯,过程中使用的数据,恢复原值
path.remove(path.size() - 1);
sum -= candidates[i];
}
}
实现代码
public class ArrayZhSum40 {
public static void main(String[] args) {
int[] candidates = {2, 5, 2, 1, 2};
List<List<Integer>> resultList = combinationSum2(candidates, 5);
System.out.println(JSON.toJSONString(resultList));
candidates = new int[]{10, 1, 2, 7, 6, 1, 5};
resultList = combinationSum2(candidates, 8);
System.out.println(JSON.toJSONString("---" + resultList));
}
public static List<List<Integer>> combinationSum2(int[] candidates, int target) {
if (candidates == null || candidates.length == 0) {
return null;
}
Arrays.sort(candidates);
List<List<Integer>> resultList = new ArrayList<>();
dfsNum(0, candidates, target, 0, resultList,
new ArrayList<Integer>());
return resultList;
}
public static void dfsNum(int start, int[] candidates, int target, int sum, List<List<Integer>> resultList,
List<Integer> path) {
if (target < sum) {
return;
}
if (target == sum) {
resultList.add(new ArrayList<>(path));
return;
}
for (int i = start; i < candidates.length; i++) {
//分层中使用过的元素直接不在用
if (i > start && candidates[i] == candidates[i - 1]) {
continue;
}
if (candidates[i] > target) {
break;
}
sum += candidates[i];
path.add(candidates[i]);
//叶子中,不使用已经使用过的元素
dfsNum(i + 1, candidates, target, sum, resultList, path);
path.remove(path.size() - 1);
sum -= candidates[i];
}
}
}