题目
给定一个候选人编号的集合 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]; } } }