一、前言
参考文献:代码随想录
今天的主题是回溯算法,二叉树章节终于刷过去了,今天的主要任务是了解回溯算法和他的作用,以及模板。
回溯算法的主要作用是解决如下问题:
今天所解决的问题就是组合问题。
回溯是递归的附带品,所以回溯的模板于递归地模板大差不差:
void backtracking(参数)
{
if (终止条件)
单层递归和回溯
return;
}
模板看着不难,那就让我们来解决今天的题目吧!
二、组合:
1、思路:
看到这个题目,其实就是一个排列问题,所以可以用暴力的方法解决,但是我们并不知道嵌套多少层for循环,因为k(循环次数)是一直变化的,所以我们并不好去暴力,这里就要用到回溯了,也就是在递归里参合着循环。
2、代码如下:
class Solution {
private:
// 一个是一维数组记录组合,result返回集合
vector<int> path;
vector<vector<int>> result;
// 参数为n,k之外还有起始位置,利用树型结构来抽象推理
void backTracking (int n, int k, int InStart) {
// 长度符合终止
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = InStart; 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;
}
};
在for循环中,我们需要有一个插入和递归的操作,但是其中最重要的是:
path.pop_back();
这是一个回溯的操作,方便后续的组合利用。
3、剪枝:
这里剪枝的操作实质上是一个对代码进行优化的过程,例如:
这就涉及到了时间的浪费,所以需要改变一下,for循环的参数结构 。
看完卡哥的视频后,我其实没有怎么理解,但是有一个公式代替size():
n - (k - path.size()) + 1
这个表示,至多从哪里开始排列,比入n = 4, k = 3,则说明之多可以从2开始排列,234,但是3就不行了。
代码如下:
class Solution {
private:
vector<int> path;
vector<vector<int>> result;
void backtracking(int n, int k, int InStart) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = InStart; i <= n - (k - path.size()) + 1; 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;
}
};
今日学习时间:1小时;
leave message:
He was still too young to know that the heart's memory eliminates the bad and magnifies the good.
当时他还太年轻,不知道人的内心会删除不好的记忆,放大美好记忆。