递归是程序设计中的一种算法。一个过程或函数直接调用自己本身或通过其他的过程或函数调用语句间接地调用自己的过程或函数,称为递归过程或函数。
例子一:打靶
面试1:一个射击运动员打靶,靶一共有10环,连开10枪打中90环的可能性有多少种?
解析:靶上一共有10种可能——1环到10环,还有可能脱靶,那就是0环,加在一起公有11种可能。
方法1:使用循环
for(i1=0;i1<=10;i1++) for(i2=0;i2<=10;i2++) for(i3=0;i3<=10;i3++) ... for(i10=0;i10<=10;i10++) { if(i1+i2+i3+...+i10==90) print(); }
但是,上面的循环程序虽然解决了问题,但时间复杂度和空间复杂度无疑是很高的,比较好的办法当然是采用递归的方式。
方法二:
递归的条件由以下4步完成:
1)如果出现这种情况,即使后面每枪都打10环也无法打够总环数90,这种情况下就不用再打了,则退出递归。代码如下:
if(score<0||score>(num+1)*10) //次数num为0~9
{
return;
}
2)如果满足条件且打到最后一次(因为必须打10次),代码如下:
if(num==0)
{
output();
return;
}
3)如果没有出现以上两种情况则执行递归,代码如下:
for(int i=0;i<=10;++i)
{
//这里实际上为了方便把顺序倒了过来,store[num]是最后一次打的出现的环数
//store[9]第10次打出现的环数,store[8]第9次打出现的环数,...,store[0]第一次打出现的环数
store[num]=i;//每一次打都11种环数可以选择
Cumput(score-i,num-1,store);
}
4)打印函数,符号要求的则把它打印出来,代码如下:
void output(int [] store)
{
for(int i=9;i>=0;--i)
cout<<store[i]<<" ";
cout<<endl;
sum++;
}
完整代码:
#include<iostream> #include<vector> using namespace std; long long global=0; vector<vector<int> > res; void Cumput(int score,int n,vector<int> &tmp) { if(score<0||score>(n+1)*10) return; if(n==0) { global++; tmp.push_back(score); res.push_back(tmp); tmp.pop_back(); return; } for(int i=0;i<11;i++) { tmp.push_back(i); Cumput(score-i,n-1,tmp); tmp.pop_back(); } } int main() { vector<int> tmp; Cumput(90,9,tmp); cout<<global<<endl; for(auto a:res) { for(auto v:a) cout<<v<<" "; cout<<endl; } }
#include<iostream> #include<vector> using namespace std; vector<vector<int> > res; void Cumput(int score,int n,vector<int> &tmp) { if(score<0||score>n*10) return; if(n==0&&score==0) { res.push_back(tmp); return; } for(int i=0;i<11;i++) { tmp.push_back(i); Cumput(score-i,n-1,tmp); tmp.pop_back(); } } int main() { vector<int> tmp; Cumput(90,10,tmp); cout<<res.size()<<endl; }
例子二:
八皇后问题:
从每一行开始填充皇后检查是否满足要求,因此,如果是有效的皇后满足的条件是:
1)选择的列与前面已经防止皇后的列不在同一列。
2)检查从改行开始的第一行的主对角线是否满足要求
3)检查从该行开始到第一行的副对角线是否满足要求
#include<iostream> #include<string> #include<vector> using namespace std; class Solution { public: vector<vector<string> > solveNQueens(int n) { vector<string> str(n,string(n,'.')); vector<vector<string> > res; helper(str,n,0,res); return res; } void helper(vector<string> &str,int n,int start,vector<vector<string> > &res) { if(start==n) { res.push_back(str); return; } for(int col=0; col<n; col++) { if(isValid(str,start,col)) { str[start][col]='Q'; helper(str,n,start+1,res); str[start][col]='.'; } } } bool isValid(vector<string> &str,int row,int col) { int i,j; for(i=0; i<row; i++) { if(str[i][col]=='Q') return false; } for(i=row-1,j=col-1; i>=0&&j>=0; i--,j--) { if(str[i][j]=='Q') return false; } for(i=row-1,j=col+1; i>=0&&j<(int)str.size(); i--,j++) { if(str[i][j]=='Q') return false; } return true; } }; int main() { Solution s; vector<vector<string> > result=s.solveNQueens(8); cout<<result.size()<<endl; for(auto a:result) { for(auto v:a) cout<<v<<endl; cout<<endl; } }
例子三:求字符子集
见:http://www.cnblogs.com/wuchanming/p/4149941.html
例子四:0-1背包问题
#include<iostream> #include<vector> using namespace std; void helper(vector<int> &num,int m,int n,int start,vector<vector<int> > &res) { if(m==0) { res.push_back(num); return; } if(m<0) return; for(int i=start; i<=n; i++) { num.push_back(i); helper(num,m-i,n,i+1,res); num.pop_back(); } } vector<vector<int> > calFun(int n,int m) { vector<vector<int> > res; vector<int> num; helper(num,m,n,1,res); return res; } int main() { vector<vector<int> > res=calFun(7,8); cout<<res.size()<<endl; for(auto a:res) { for(auto v:a) cout<<v<<" "; cout<<endl; } }