回溯法解决的问题都可以抽象为树形结构(N叉树),回溯法解决的问题都是在集合中递归查找子集,集合的大小构成了树的宽度,递归的深度构成树的深度。【参考:代码随想录】
回溯法模板:
- 回溯函数模板返回值以及参数
void backtracking(参数)
- 回溯函数终止条件
if (终止条件) {
存放结果;
return;
}
- 回溯搜索的遍历过程
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
一、组合
77. 组合
vector> res; vector path; vector > combine(int n, int k) { BackTracking(n, k, 1); return res; } void BackTracking(int n, int k, int start) { // 递归终止条件 if (path.size() == k) { res.push_back(path); return; } // 递归逻辑 for (int i = start; i < n; i++) { path.push_back(i); BackTracking(n, k, i + 1); // 回溯 path.pop_back(); } }
本题即使采用暴力搜索,也很难完成,因此需要用到回溯法。递归的过程如下图所示(来源:代码随想录):
递归可以进行枝剪,本题递归中的for循环代码可以进行如下修改:
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++)216. 组合总和 III
vector> res; vector path; int sum = 0; vector > combinationSum3(int k, int n) { BackTracking(k, n, 1); return res; } void BackTracking(int k, int n, int start) { if (path.size() == k) { if (sum == n) { res.push_back(path); } return; } for (int i = start; i <= 9; i++) { if (i >= n) return; path.push_back(i); sum += i; BackTracking(k, n, i + 1); sum -= i; path.pop_back(); } }
本题与上一题类似,不再赘述。
二、分隔 三、子集 四、排列 五、棋盘问题 六、其它


