斐波那契数列的几种解法

1,194 阅读2分钟

斐波那契数列定义:

斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987........

这个数列从第3项开始,每一项都等于前两项之和。

1.常规解法---递归

根据第n项的值等于n-1和n-2的值之和这个特性,代码如下:

public class Fibonacci {

	public static int Fib(int N) {
		if (N < 3)
			return 1;
		else
			return Fib(N - 1) + Fib(N - 2);
	}

	public static void main(String[] args) {
		int num = Fib(10);
		System.out.println(num);
	}
}

这种方法的最大缺陷就是重复计算的次数太多了,导致时间复杂度高,比如当n=3时

1. Fib1(3)=Fib1(2)+Fib1(1)
2. 计算Fib1(1)          第一次计算
3. 计算Fib1(2)          第二次计算
4. 计算Fib1(2)+Fib1(1)  第三次计算

就需要计算三次,时间复杂度:O(2^N),空间复杂度:O(N)

2.递归+全局数组

由于第一种方式重复计算的次数过多,为了避免我们可以建立一个类似于全局变量的数组来存储已经计算出来的数列项,在每一次递归时直接取出来前两个值,省去重复计算。代码如下:

public class FibArray {
	
	public static int[] array = new int[20];

	public static int Fib(int n) {
		if (n <= 1)
			return n;
		if (array[n] != 0)
			return array[n];
		else
			return array[n] = Fib(n - 1) + Fib(n - 2);

	}
	
	public static void main(String[] args) {
		int num = Fib(10);
		System.out.println(num);
	}
}

此种方法相当于缓存了前面的值,很大程度的减小了第一种方法(递归实现斐波那契数列)的时间复杂度,缺点是需要另外开辟数组内存,数组的长度是固定的,不能动态调整。
时间复杂度:0(N), 空间复杂度:0(N)

3.循环实现

public class FibForEach {
	public static int Fib(int n) {
		int first = 1;
		int second = 1;
		int ret = 0;
		for (int i = 3; i <= n; i++) {
			ret = first + second;
			first = second;
			second = ret;
		}
		return second;
	}
	
	public static void main(String[] args) {
		int num = Fib(10);
		System.out.println(num);
	}
}

循环的方式省去了数组这个不定的因素,优点:时间复杂度和空间复杂度最低,而且可读性高 时间复杂度:O(N)
空间复杂度:O(1)(创建了四个对象,是常数,所以可忽略不计)

4.斐波那契通项公式

斐波那契还存在一个通项公式:

在数值较大的时候是尤为方便的
代码如下

public class FibAll {

	static double ROOT_OF_FIVE = Math.sqrt(5.0);

	static double Fib(int n) {
		return (Math.pow(((1 + ROOT_OF_FIVE) / 2.0), n) / ROOT_OF_FIVE
				- Math.pow(((1 - ROOT_OF_FIVE) / 2.0), n) / ROOT_OF_FIVE);
	}

	public static void main(String[] args) {
		double num = Fib(10);
		System.out.println(num);
	}
}