斐波那契数列计算
0 斐波那契数列
费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数、斐波那契数列、费氏数列、黄金分割数列。
在数学上,费波那契数列是以递归的方法来定义:
\[F_{0}=0\\ F_{1}=1\\ F_{N}= F_{N-1}+F_{N-2} \]
用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出。首几个费波那契系数是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……(OEIS中的数列A000045)
1 朴素递归方法
递归方法的思路是一种从后往前计算的思路。当我需要计算第N个值时,需要得到第N-1和第N-2个的值。代码如下所示。
根据这个思路,我们递归算法的递归树如下所示:
public static int getFabN_reccurent(int N) {
if (N < 1) {
return 0;
}
if (N==1 || N==2) {
return 1;
}
return getFabN_reccurent(N-1)+getFabN_reccurent(N-2);
}
这个算法的的一大缺点就是一些值被重复计算,例如上图中的N-4及其子树被计算了4次。该算法的整体时间复杂度为指数级别,严格的时间下界为
\[Ω(Φ^2) = (\frac{(1-\sqrt{5})}{2})^n \]
2 线性计算方法
线性计算方法的思路是从前往后计算,从第一个斐波那契数列值开始,直到第N个结束。该算法的时间复杂度较上面的要好很多,为显性复杂度。
\[O(N) \]
public static int getFabN_linear(int N) {
if (N < 1) {
return 0;
}
if (N==1 || N==2) {
return 1;
}
int first = 1;
int second = 1;
int temp = 0;
for(int i=3;i<=N;i++) {
temp = first+second;
first = second;
second = temp;
}
return second;
}
3 组合数学计算方法
很有意思的是,斐波那契数列出现在了杨辉三角当中(二项系数)。
根据维基百科中的介绍,有如下的通项公式。
\[{\displaystyle F_{n}=\sum _{k=0}^{\left\lfloor {\frac {n-1}{2}}\right\rfloor }{\tbinom {n-k-1}{k}}} \]
代码如下所示:
public static int factorial(int n) {
//计算阶乘
return (n > 1) ? n * factorial(n - 1) : 1;
}
public static int combination(int M,int n) {
//计算组合,M中取n个
return (M >= n) ? factorial(M) / factorial(M - n) / factorial(n) : 0;
}
public static int getFabN_Combinartic(int N) {
int allSum = 0;
for(int k=0;k<=((N-1)/2);k++) {
allSum += combination(N-k-1,k);
}
return allSum;
}
该算法的运算复杂度主要集中,在计算组合数上,combination函数的时间复杂度为
\[O(N) \]
函数getFabN_Combinartic在不考虑combination的情况下的时间复杂度也是
\[O(N) \]
那么这个方法的整体时间复杂度应该是
\[O(N^2) \]
谢谢
算是开始学习算法的第一篇博客,有不足请指正。