递归算法:
程序直接或间接调用自身的编程技巧称为递归算法。
直接或间接调用自身的函数称为递归函数。
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。
ps:关键在于找出递归定义与终止条件。
递归:
1.通过递归调用将整个问题层层分解成处理方法相似的子问题;
2.通过回溯,按照递归关系将子问题的解整理成整个问题的解;
3.分解子问题时,如当前问题有多种情况需要考虑,要进一步进行枚举;
4.递归关系可能是一个公式,也可能是一个前提条件。
例题
1.1到100求和。
递归定义:f(n)=f(n-1)+n
终止条件:f(1)=1
代码:
int fn(int n)
{
if(n<=1)return 1;
else return (n+fn(n-1));
}
2.N!
递归定义:N!=(N-1)!*N
终止条件:1!=1;0!=1;
代码:
int fact(int N)
{
if(N<=1)return 1;
else return (fact(N-1)*N);
}
3.最大公约数(欧几里得算法)
递归定义:gys(m,n)=gys(n,m%n);
终止条件:n=0即gys(m,0)=m;
代码:
int gys(int m,int n)
{
if(n==0)return m;
else return (gys(n,m%n));
}
4.年龄问题
递归条件: age(n)=age(n-1)+2;
终止条件:age(1)=10;
代码:
int age(int n)
{
if(n==1)return 10;
else return (age(n-1)+2);
}
5.快速幂a^b
求 a^b 的值
eg:当b=1 return a;
当b=0,return 1;
当b=5时,
a5=a*(a4)
=a*(a2*a2)
=a*((aa)(a*a)
typedef long long ll;//自定义语句,long long表示64位
ll binaryPow(ll a, ll b){
if(b == 1)
return a;
else if(b % 2 == 1)
return a * binaryPow(a, b - 1) ;
else{
ll num = binaryPow(a, b/2) ; //优化
return num * num ;// 不直接写成return binaryPow(a, b/2, m) * binaryPow(a, b/2, m),这样可以减少递归的次数,降低时间复杂度
}
6,全排列问题:
先排高位,再排下一位,以此类推。要用枚举(即暴力,所有问题全部列出)。
eg:
//表示从元素k~m的全排列,作为前k—1个元素的后缀,
void Perm(int list[], int k, int m)
{
//构成了一次全排列,输出结果
if(k==m)//表示全排列只剩一个数,即它自身
{
for(int i=0;i<=m;i++)
cout<<list[i]<<" ";
cout<<endl;
}
else
//至少有两位以上的数,需要排列。在数组list中,产生从元素k~m的全排列
for(int j=k;j<=m;j++)
{
swap(list[k],list[j]);//k位确定好了
Perm(list,k+1,m);//k+1到m做全排列
swap(list[k],list[j]);//注意此处!!需要恢复到原始的数据,不能影响下一次数据的取值,要交换两次(恢复现场)
}
}
`
半数集问题:
给定一个自然数n,由n开始依次产生半数集set(n)中的数:
(1)n∈set(n)
(2)在n左边加上一个数,当该自然数不能超过最近添加的数的一半。
(3)按照此规律处理,直至不能再添加新的数。
ps:半数集是多重集。
对于给定自然数n,编程半数集set(n)中的元素个数。
eg:set(8)={18,28,128,138,38,148,248,1248}
前面加的数,是后一个数的1到n/2.
设set(n)中元素的半数集个数为f(n),则
(其中1表示该数本身,也属于半数集内)。
代码:
int bsj(int n)
{
int ans=1;
if (n>1)
for(int i=1;i<=n/2;i++)
ans+=bsj(i);//时间复杂度高,调用若干次
return ans;
}
优化方法:记忆化搜索(记录已经求出来的结果),特点:空间换时间。
int a[1001];//该数组储存下标为i的半数集的元素个数。一般数组的默认值为0,若下标为i的数组默认值不为0,则表示该下标为i的元素个数已经求过,这样就不需要再递归调用了
int bsj(int n)
{
int ans=1;
if(a[n]>0)return a[n]; //已经求出
else for(int i=1;i<=n/2;i++)
ans+=bsj(i);
a[n]=ans; //保存结果
return ans;
}
`