数据结构与算法复习1--递归
一.概念
递归=递推+回归
1.递推:将原有的问题不断分解成子问题,直到达到结束条件,返回最近子问题的解
2.回归:逆向逐一回归,最终到达递推开始的原问题,返回原问题的解
*递归必须有结束条件
二.递归问题分析
1.5!逻辑分析
①递归过程
②回归过程
*递归的深度就是栈空间的问题
③时间复杂度分析
T(n)=T(n-1)+1---"1"代表一次乘法
=T(n-2)+1+1
=.........
=n
2.一棋盘麦子问题
印度有一个古老的传说:舍罕王打算奖赏国际象棋的发明人——宰相:西萨·班·达依尔。国王问他想要什么,他对国王说:“陛下,请您在这张棋盘的第1个小格里,赏给我1粒麦子,在第2个小格里给2粒,第3小格给4粒,以后每一小格都比前一小格加一倍。请您把这样摆满棋盘上所有的64格的麦粒,都赏给您的仆人吧!”国王觉得这要求太容易满足了,就命令给他这些麦粒。当人们把一袋一袋的麦子搬来开始计数时,国王才发现:就是把全印度甚至全世界的麦粒全拿来,也满足不了那位宰相的要求。 那么,宰相要求得到的麦粒到底有多少呢?总数为:
分析:64格子,每一格是前一格的两倍
①:S=1+;
运算等比数列,乘倍数
②:2S=;
③;S=-1
称为爆炸增量函数
3.神奇的兔子问题即斐波那契数列问题
假设一对初生兔子要一个月才到成熟期,而一对成熟兔子每月会生一对兔子,那么,由一对初生兔子开始,12 个月后会有多少对兔子呢?
分析:
图源:知乎
斐波那契数列特性
斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……
第一项和第二项是1,之后的每一项为之前两项的和
算法①:
//1.爆炸增长
Fib1(int n){
if(n<1){
return -1;
}
if(n==1||n==2){
return 1;
}
return Fib1(n-1)+Fib1(n-2);
}
时间复杂度:指数级
算法②
记录当前两项的值,只要一次加法得到当前值,辅助数组记录当前结果,使用动态规划方法
//2.数组动态规划
Fib2(int n){
if(n<1)
return -1;
int *a=new int[n+1];//定义一个长度为n+1的数组,0空间未使用
a[1]=a[2]=1;
for(int i=3;i<=n;i++){
a[i]=a[i-1]+a[i-2];
}
return a[n];//查表法
}
//动态分配的内存用完必须释放
temp=a[n];
delete []a;
return temp;
时间复杂度:O(n)
算法③
分析:利用迭代法,不浪费中间空间,利用两个常量变量
初始S1,S2=1;
i=3:s2=s1+s2=2 s1=s2-s1=1
i=4:s2=s1+s2=3 s1=s2-s1=2
i=5:s2=s1+s2=5 s1=s2-s1=3
...............................................
//3.利用常熟变量
Fib3(int n){
int i,s1,s2;
if(n,1)
return -1;
if(n==1||n==2)
reutrn 1;
s1=1,s2=1;
for(int i=3;i<=n;i++){
s2=s1+s2;//辗转相加
s1=s2-s1;//记录前一项
}
return s2;
}
时间复杂度:O(n)
空间复杂度:O(1)
算法④
实现最小复杂度Olog(n)对数级,不常用,弊端较大
//4.降低时间复杂度-二分法
Matrix2By2 MatrixPower(unsigned int n)
{
Matrix2By2 Init = { 1, 1, 1, 0 };
Matrix2By2 ret;
if (1 == n)
{
ret = Init;
}
else if (0 == (n & 1))
{
ret = MatrixPower(n / 2); //偶数处理
ret = Mul(ret, ret);
}
else if (1 == (n & 1))
{
ret = MatrixPower((n - 1) / 2); //奇数处理
ret = Mul(ret, ret);
ret = Mul(ret, Init);
}
return ret;
}
long long Fib4(unsigned int n)
{
if (n < 2)
return n;
else
{
Matrix2By2 ret = MatrixPower(n - 1);
return ret.m00;
}
}
@ 分析图均为自己制作禁止转载,确有需求请注明出处