斐波那契数列计算

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个的值。代码如下所示。
根据这个思路,我们递归算法的递归树如下所示:

java 费波纳茨数列 费波那契数列公式_斐波那契数列

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 组合数学计算方法

很有意思的是,斐波那契数列出现在了杨辉三角当中(二项系数)。

java 费波纳茨数列 费波那契数列公式_时间复杂度_02

根据维基百科中的介绍,有如下的通项公式。

\[{\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) \]

谢谢

算是开始学习算法的第一篇博客,有不足请指正。