No.1 递归版
lom recur(lom x)
{
if(n<=1) return x;
else return recur(x-1)+recur(x-2);
}
简洁明了,一气呵成,将递归的精髓用的淋漓尽致,但是你求一个第一万个数试试,保证很好玩,嗯,递归栈也是有限的,默认栈空间大小只有8M。一般来说,8M的栈空间对于一般程序完全足够。如果8M的栈空间不够使用,那么就需要重新审视你的代码设计了。
No.2 递归1.0版
lom a[10000000];
lom recur(lom x)
{
if(n < 2) return n;
else return a[n]=recur(n-1)+a[n-2];
}
用数组保存已经求过的值,but,终究还是递归,虽然时间复杂度降到了O(n),但递归栈还是很深
No.3送代版
a[1]=a[2]=1;
for(lom i=3;i<=10000;i++)
a[i]=a[i-1]+a[i-2];
这个不解释
重点来了啊,扶稳坐好了
No.n-1矩阵快速幂版:
#include<bits/stdc++.h>
#define lom unsigned long long
using namespace std;
void matrixmuti(lom A[2][2],lom B[2][2],lom C[2][2])
{
lom temp[2][2]; //临时存储,参数的传递
memset(temp,0,sizeof(temp));
//矩阵求法
temp[0][0]=A[0][0]*B[0][0] + A[0][1]*B[1][0];
temp[0][1]=A[0][0]*B[0][1] + A[0][1]*B[1][1];
temp[1][0]=A[1][0]*B[0][0] + A[1][1]*B[1][0];
temp[1][1]=A[1][0]*B[0][1] + A[1][1]*B[1][1];
memcpy(C,temp,sizeof(temp));//copy
}
lom feibo(lom n)
{
if(n<=1) return n;
lom ans[2][2]={1,0,0,1};//结果矩阵
lom A[2][2]={1,1,1,0};//单位矩阵
while(n>0)//快速幂
{
if(n&1) matrixmuti(A,ans,ans);
n>>=1;
matrixmuti(A,A,A);
}
return ans[0][1];
}
int main()
{
cout<<feibo(10);
return 0;
}
时间复杂度降到O(log n),
没学过线性代数的童鞋看起来会很难理解,不过没关系,去百度一下矩阵乘法就行,还有快速幂,其实也是一种常见的算法,不懂快速幂的可以用笔在纸上模拟一下,快速幂:https://blog.csdn.net/qq_41431457/article/details/88355867
看一波讲解:
矩阵快速幂解法是一种高效的解法,需要推导,对此不感兴趣的可直接看最终推导结果。学过数学的都知道,下面的式子成立是显而易见的,不多做解释。
如果a为矩阵,等式同样成立,后面我们会用到它。
假设有矩阵2*2矩阵A,满足下面的等式:
可以得到矩阵A:
因此也就可以得到下面的矩阵等式:
再进行变换如下:
以此类推,得到:
实际上f(n)就是矩阵 中的A[0][0],或者是矩阵 中的A[0][1]。
那么现在的问题就归结为,如何求解 ,其中A为2*2的矩阵。
该算法的关键部分在于对 的计算,它利用了我们开始提到的等式,对奇数和偶数分别处理。假设n为9,初始矩阵为E则计算过程如下:
- 9为奇数,则计算E*A,随后A变为A*A,n变为9/2,即为4
- 4为偶数,则结果仍为E*A,随后A变为 ,n变为4/2,即2
- 2为偶数,则结果仍未E*A,随后变A变为 , n变为2/2,即1
- 1为奇数,则结果为E*(A^8)*A
系好安全带啊,飞机起飞了啊
No.N终极通项公式版
lom slove(lom n)
{
double a=(1.0+sqrt(5.0))/2.0;
double b=(1.0-sqrt(5.0))/2.0;
a=pow(a,n);
b=pow(b,n);
return (lom)((a-b)/sqrt(5.0)+0.5);
}
公式:
是不是看起来非常简单,像发现了新大陆,但是我告诉你,这个只能求前76项,为什么?因为涉及到无理数,还不能取余,double都不够存,除非你开一个非常大的数组模拟小数,大到经过 以long long的最大为指数次幂运算后,丢失的精度还可以忽略不计