js获取菲波那契数列的第N个元素

概序

菲波那契数列,大致可以描叙为a(n) = a(n-1) + a(n-2) (a > 2)。类似于这样[1, 1, 2, 3, 5, 8, 13 ...],下面我们用js来实现一下:


1.递归

1
2
3
4
5
6
7
8
9
10
var a = function(n) {
if (n === 1 || n === 2) {
return 1
} else {
return a(n - 1) + a(n - 2)
}
}
console.time('a(44)')
console.log(a(44))
console.timeEnd('a(44)')

以上我们可以比较清晰的看出代码的思路,但是这种方法有一个致命的缺点:效率太差!

604467-20170114150610697-767833320

执行到第44个的时候,已经不能接受了。需要5s多。那我们再来改进一下:

2.闭包+缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var b = (function() {
var cache = {
1: 1,
2: 1
}
return function(n) {
if (cache[n]) {
return cache[n]
} else {
cache[n - 1] = b(n - 1)
cache[n - 2] = b(n - 2)
return cache[n - 1] + cache[n - 2]
}
}
})()

console.time('b(1200)')
console.log(b(1200))
console.timeEnd('b(1200)')

将每一步计算出来的值,保存到了缓存中。效率提升了许多:
604467-20170114151042556-1772264773

3.直接计算出该数列的值得数组,然后再从数组中取值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var c = function(n) {
var arr = [1, 1]
if (n === 1 || n === 2) {
return 1
}
for (var i = 2; i < n; i ++) {
arr[i] = arr[i - 1] + arr[i - 2]
}
return arr[n - 1]
}

console.time('c(1200)')
console.log(c(1200))
console.timeEnd('c(1200)')

这样效率又进一步提高了不少:

604467-20170114151353213-1988265003

4.直接使用数学表达式

从网上得出菲波那契数列是有数学表达式的:
604467-20170114151555010-1595503507

1
2
3
4
5
6
7
var d = function(n) {
return (1/(Math.pow(5, 1/2))) * (Math.pow((1 + Math.pow(5, 1/2))/2, n) - Math.pow((1 - Math.pow(5, 1/2))/2, n))
}

console.time('d(1200)')
console.log(d(1200))
console.timeEnd('d(1200)')

现在我们来看一下效果:
![604467-20170114151947291-1309083018](https://img.longyouwei.com/604467-20170114151947291-1309083018.png?imageView2/0/q/75|watermark/2/text/bG9uZ3lvdXdlaS5jb20=/font/5a6L5L2T/fontsize/240/fill/IzAwMDAwMA==/dissolve/100/gravity/SouthEast/dx/10/dy/10

)

总结一下:以上方法都有利有弊,有人指出直接使用数学表达式会产生js计算精度问题,希望大家权衡考量,并且提出更好的建议。

坚持原创技术分享,您的支持将鼓励我继续创作!