如何优雅的解决斐波那契数列

如何优雅的解决斐波那契数列

斐波那契数列是一个出镜率极高,这个问题非常有意思,它看似简单,其实里面有很多的门道,从最初级的程序员到算法高手,都能写出来答案,那么我们尝试去研究下它的“最叼”解。

常见的解法以及分析

  • 时间复杂度:O(n^2)
let fibnacci = n => 
	n <= 0 ? 0 : n == 1 ? 1 : fibnacci(n-2) + fibnacci(n-1); 

递归改为动态规划

  • 时间复杂度:O(n)
let fibnacci = n => {
	if(n == 0) return 0p;
	let a1 = 0, a2 = 1;
	for(let i = 1; i < n; i++){
		[a1, a2] = [a2, a1+a2];
	}
	return a2;
}

更好的解法?

数学思想——通项公式

let fibnacci = n =>
(Math.pow((1 + Math.sqrt(5))/2, n) - (Math.pow(1 - Math.sqrt(5))/2, n)) / Math.sqrt(5)

注意!通项公式使用了内置函数 Math.pow,它的时间复杂度并不低,思路上是正确的,我们就从实现上改一改

自己实现一个Math.pow() ——让幂运算的时间复杂度是无限接近 O(log(n))

let pow = (x ,y) => {
	var r = 1;
	var v = x;
	while(n) {
		if(n % 2 == 1){
			r *= v;
			n-=1
		}
		v = v * v;
		n = n / 2
	}
	return r;
}

此外这个实现方式有一些瑕疵,需要取整

利用矩阵的方式求斐波那契数列

在这里插入图片描述

矩阵乘法(此时不得不感叹大学里学的线性代数都还给老实了。。。)

在这里插入图片描述

我们将这种数学思想实现的pow方法整理一下

let matrix22_pow = (x, n) => {
	var r = [[1, 0][0, 1]]
	var v = x
	while(n){
		if(x % 2 == 1) {
			r = matrix_mul(r, v)
			n -= 1;
		}
		v = matrix_mul(v, v)
		n = n / 2
	}
	return r
}

在将次pow方法套用到斐波那契数列的解法中

最终解

let fibnacci = n => 
	n <= 0 ? 0 : 
		matrix_mul( [[0, 1],[0, 0]] , matrix22_pow([[0, 1],[1, 1]], n-1) )[0][1]  
发布了263 篇原创文章 · 获赞 40 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/jbj6568839z/article/details/104698486