1、组合问题
-
题目链接:77. 组合
-
题解
- 把组合问题抽象为如下树形结构
图中每次搜索到了叶子节点,我们就找到了一个结果。相当于只需要把达到叶子节点的结果收集起来,就可以求得n
个数中k
个数的组合集合。 - 最难理解的是单层搜索的过程
回溯法的搜索过程就是一个树型结构的遍历过程,在如下图中,可以看出for
循环用来横向遍历,递归的过程是纵向遍历。
如此我们才遍历完图中的这棵树。for
循环每次从startIndex
开始遍历,然后用path
保存取到的节点i
。代码如下:
可以看出for (int i = startIndex; i <= n; i++) { // 控制树的横向遍历 path.push_back(i); // 处理节点 backtracking(n, k, i + 1); // 递归:控制树的纵向遍历,注意下一层搜索要从i+1开始 path.pop_back(); // 回溯,撤销处理的节点 }
backtracking
(递归函数)通过不断调用自己一直往深处遍历,总会遇到叶子节点,遇到了叶子节点就要返回。backtracking
的下面部分就是回溯的操作了,撤销本次处理的结果。
- 把组合问题抽象为如下树形结构
-
代码
class Solution { private: vector<vector<int>> result; // 存放符合条件结果的集合 vector<int> path; // 用来存放符合条件结果 void backtracking(int n, int k, int startIndex) { if (path.size() == k) { result.push_back(path); return; } for (int i = startIndex; i <= n; i++) { path.push_back(i); // 处理节点 backtracking(n, k, i + 1); // 递归 path.pop_back(); // 回溯,撤销处理的节点 } } public: vector<vector<int>> combine(int n, int k) { backtracking(n, k, 1); return result; } };
- 时间复杂度:
O(n * 2^n)
- 空间复杂度:
O(n)
- 时间复杂度:
-
给出回溯算法模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}