// 回溯算法核心函数,遍历子集问题的回溯树 voidbacktrack(int[] nums, int start) {
// 前序位置,每个节点的值都是一个子集 res.add(newLinkedList<>(track)); // 回溯算法标准框架 for (inti= start; i < nums.length; i++) { // 做选择 track.addLast(nums[i]); // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(nums, i + 1); // 撤销选择 track.removeLast(); } } }
组合问题
组合就是对应长度的子集
实际上就是在子集问题的基础上加一层判断,只有当子集中元素的个数等于组合数的长度时才记录
比如我们要组合 nums = [1,2,3]中的两个数
[ [1,2],[1,3],[2,3] ]
classSolution {
List<List<Integer>> res = newLinkedList<>(); // 记录回溯算法的递归路径 LinkedList<Integer> track = newLinkedList<>();
// 主函数 public List<List<Integer>> combine(int n, int k) { backtrack(1, n, k); return res; }
voidbacktrack(int start, int n, int k) { // base case if (k == track.size()) { // 遍历到了第 k 层,收集当前节点的值 res.add(newLinkedList<>(track)); return; } // 回溯算法标准框架 for (inti= start; i <= n; i++) { // 选择 track.addLast(i); // 通过 start 参数控制树枝的遍历,避免产生重复的子集 backtrack(i + 1, n, k); // 撤销选择 track.removeLast(); } } }
从最简单的子集问题推广到需要加判断条件和start的组合问题以及加判断条件和used数组的排列问题
排列组合复杂情况
对于回溯的排列组合问题上述元素均为无重复且不可复选的情况
实际可以分为三类
无重复不可复选
有重复不可复选
无重复可复选
有重复可复选的情况本质和无重复可复选一样(既然可复选,元素重不重复都一样,等价于无重复可复选)
无重复不可复选就是最基本的情况,上面已经讲过了
下面谈谈有重复不可复选的情况
子集问题
classSolution {
List<List<Integer>> res = newLinkedList<>(); LinkedList<Integer> track = newLinkedList<>();