提示
-
1 <= n <= 20
-
1 <= k <= n
看到这个题目第一时间我们可能会想到暴力循环来做,但是我们会发现这样是不行的,因为k是变量,所以循环的层数我们是不确定的,这个时候我们就可以用dfs+回溯来做,在dfs的每一层递归中套一层循环,并且每一层递归我们都可以调整搜索的剩余区间,从而搜索到符合要求的k个数的组合,下面我们看代码
为了不让函数参数过多影响阅读,我们将要返回的答案集合和在递归中符合条件返回的集合都定义为全局变量
class Solution{
vector<vector> ans;
vector temp;//在dfs中满足出口条件添加到ans集合中
};
主函数中我们还要传入n,k两个参数以及一个非常关键的参数,这个参数就表示着dfs的每一层递归中循环的起始搜索位置,因为题目是要求从1-n中找出k个数,所以我们在主函数中首先传入1
class Solution {
public:
vector<vector> ans;
vector temp;
vector<vector> combine(int n, int k) {
dfs(n, k, 1);
return ans;
}
};
接下来是关键的dfs函数,首先出口条件是temp集合的长度等于k,这时表示已经搜索到了一个组合有k个数,因此我们要把这个组合添加到ans集合中,然后终止这一层递归,也是回溯到上一层递归去,来进行另一种组合的搜索
void dfs(int n, int k, int depth) {
if(temp.size() == k) {
ans.push_back(temp);
return;
}
}
这里注意我们是用了vector的push_back()方法将当前temp集合添加到了ans集合的末尾,因为题目中是说了不用管答案中的顺序的,因此我们不用管添加顺序。
前面说了我们是在dfs的每一层递归中去套一层循环,以此形成k层循环的查找,接下来就是一层for循环,循环变量的初值是startPos,我们之前提到了,除了n,k之外还有一个十分关键的参数,这个参数控制了每层循环搜索的区间
void dfs(int n, int k, int depth) {
if(temp.size() == k) {
ans.push_back(temp);
return;
}
for(int i = startPos; i <= n; i++) {
temp.push_back(i);
dfs(n, k, i + 1);
temp.pop_back();
}
}
现在我们来假设一下,
第一层递归选中了1这个数字,那么在接下来这层递归中1就不能再出现在搜素区间里了,就应该从2开始,同理2,3,4…也是一样,所以这个参数不是代表递归深度,而是代表每一层递归的搜索区间的起始搜索位置
在循环中temp.push_back(i)
代表选中i这个数字,然后进入下一层递归,但是这里要注意,如果进入下一层递归后当前我们选中的数字不符合要求,我们就需要退回上一步的状态,也就是选中这个数字之前的状态,所以就需要temp.pop_back()
去掉我们添加的数字,返回之前的状态,这就是回溯法,“在进入下一层递归前做的事,我们需要在递归后返回到做这个事之前的状态”。下面是完整代码
完整代码:
文末
篇幅有限没有列举更多的前端面试题,小编把整理的前端大厂面试题PDF分享出来,一共有269页