如何優雅的解決斐波那契數列

如何優雅的解決斐波那契數列

斐波那契數列是一個出鏡率極高,這個問題非常有意思,它看似簡單,其實裏面有很多的門道,從最初級的程序員到算法高手,都能寫出來答案,那麼我們嘗試去研究下它的“最叼”解。

常見的解法以及分析

  • 時間複雜度: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]  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章