77. 组合
https://leetcode.cn/problems/combinations/
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。

1.本题是一个经典的回溯算法题目,怎么辨别题解需要使用回溯算法呢?
回溯法,一般可以解决如下几种问题:
2.回溯法模板
回溯三部曲:
(1)返回值以及参数
返回值一般为void。再来看一下参数,因为回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来,所以一般是先写逻辑,然后需要什么参数,就填什么参数
(2)回溯函数终止条件
什么时候达到了终止条件,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归
(3)回溯搜索的遍历过程。
for循环是横向遍历可以理解一个节点有多少个孩子,这个for循环就执行多少次
backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。
总结回溯算法模板如下:
- void backtracking(参数) {
- if (终止条件) {
- 存放结果;
- return;
- }
-
- for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
- 处理节点;
- backtracking(路径,选择列表); // 递归
- 回溯,撤销处理结果
- }
- }
3.代码
- class Solution {
- List<List<Integer>> result = new ArrayList<>();
- LinkedList<Integer> path = new LinkedList<>();
- public List<List<Integer>> combine(int n, int k) {
- combineHelper(n, k, 1);
- return result;
- }
-
- /**
- * 每次从集合中选取元素,可选择的范围随着选择的进行而收缩,调整可选择的范围,就是要靠startIndex
- * startIndex用来记录本层递归中,集合从哪里开始遍历(集合就是[1,...,n] )
- */
- private void combineHelper(int n, int k, int startIndex){
- //终止条件
- if (path.size() == k){
- result.add(new ArrayList<>(path));
- return;
- }
- for (int i = startIndex; i <= n - (k - path.size()) + 1; i++){
- path.add(i);
- combineHelper(n, k, i + 1);
- path.removeLast();
- }
- }
- }