递归
递归就是自己调用自己的过程(虽然这就话在很多博客上都这么说,但我还是要说一遍)。
但是在学习递归的过程中,千万不要像上面这么理解(ಡωಡ)
因为你会像套娃一样的套个不停(强迫症(ಡωಡ))
思路一:
所以你要把内部的递归理解为调用其他的函数,例如:
void dfs(int index){
dfs(index-1);//这里的dfs可以理解为:调用名字字一样的另一个函数
}
保持这个思路继续往下:
思路二:
在递归的过程中只要考虑特殊的状态就ok了。其实特殊的状态只有两个,那就是
1.中心
2.边界
中心可以理解为一般的情况
边界可以理解为特殊的情况
以下的教程都基于这两个思路来进行
我们通过举几个例子讲解一下:
1.全排列
将1-9这九个数字进行位数为3的全排列
就像这样子123、199、927
直接上代码(ಡωಡ)
dfs函数是这样
void dfs(int range,int index,string str){//index代表当数字范围,maxn代表当前搜索到第多少列
if (index == 0){
cout << str << endl;
}
else{
for (int i = 1; i <= range; i++){
str += i + '0';
dfs(range, index-1, str);
str.pop_back();
}
}
}
主函数是这样
int main(){
dfs(9, 3,"");//1-7的三位数字的全排列
return 0;
}
整体思路:
通过增减字符串来达到保存一次匹配成功的状态
这个例子是通过遍历数字的每一位(位数遍历从后往前,到0时停止)
看到这里可能会感觉 妙(看)不(求)可(不)言(懂),接下来进入正题。
再把上面的代码copy一遍(防丢)
void dfs(int range,int index,string str){//index代表当数字范围,maxn代表当前搜索到第多少列
if (index == 0){
cout << str << endl;
}
else{
for (int i = 1; i <= range; i++){
str += i + '0';
dfs(range, index-1, str);
str.pop_back();
}
}
}
依据思路二:
这里的中心是指:
else{//对于中心来说(相当于数字的每一位)都有9种可能,for循环就是这么来的
for (int i = 1; i <= range; i++){
str += i + '0';//增加字符串
dfs(range, index-1, str);//位数直接自键,与边界相对应
str.pop_back();//再遍历完每一种可能之后要记得将增加的删除掉,用来进行下一次的dfs
}
}
这里的边界是指:
if (index == 0){//如果到达边界,直接把str输出
cout << str << endl;
}
讲完了(ಡωಡ)
(ಡωಡ)
接下来讲组合
#include<iostream>
#include<string>
using namespace std;
int book[100];
void dfs(int range,int index,string str){
if (index == 0){
cout << str << endl;
}
else{
for (int i = 1; i <= range; i++){
if (!book[i]){
book[i] = 1;
str += i + '0';
dfs(range, index - 1, str);
str.pop_back();
book[i] = 0;
}
}
}
}
int main(){
dfs(9, 3,"");
return 0;
}
看完之后是不是觉得和排列大同小异(ಡωಡ),其实只多了一个book数组,用来记录这个数字每一位的使用情况,如果是1,表示使用过,如果是0,就是没使用,相当于去掉排列重复的部分
如果你看懂这些之后还有一些技巧
以后补充(ಡωಡ)