这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战 | 创作学习持续成长,夺宝闯关赢大奖 - 掘金 (juejin.cn)
题目链接
- 斐波那契数列 leetcode-cn.com/problems/fe…
题解及分析
斐波那契数列
写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项(即F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
思路一:迭代+滚动数组
先上leetcode题解的图
斐波那契数列只关心最后两个数的相加和,因此可以用到滚动数组的思想
解法很直白,不做太多解释:
var fib = function(n) {
const MOD = 1000000007
if (n < 2) {
return n;
}
let p = 0
let q = 0
let r = 1
for(let i = 2; i <= n; ++i) {
p = q
q = r
r = (p + q) % MOD
}
return r
}
思路二:递归
斐波那契数列天然契合递归的理念
const MOD = 1000000007
var fib = function(n) {
if(n < 2) return n
return (fib(n-1)%MOD) + (fib(n-2)%MOD)
}
这么写并不能过编译,因为在递归到边界条件之前,执行的量很可能已经很大,早已经超出限制的编译时间
观察后不难发现,递归的过程会导致很多重复的计算,比如n = 5时:
- fib(5)为fib(4)和fib(3)两个值之和
- 然后fib(4)又等于fib(3)和fib(2)两个值之和。
- *fib(3)*刚才已经求过了
- 另一个fib(3)即为fib(2)和fib(1)两个值之和
- *fib(2)*刚才也已经被求过了
对于这种重复的情景,我们可以用map来优化
const MOD = 1000000007
let map = new Map
let fib = n => {
return newFib(n)
}
let newFib = function(n) {
if(n < 2) return n
if(map.has(n)) return map.get(n)
let a = newFib(n-1) % MOD
let b = newFib(n-2) % MOD
let res = (a + b) % MOD
map = new Map([...map, [n-1, a], [n-2, b], [n, res]])
return res
}
(很抱歉不是科班出身,实在看不懂矩阵幂的解法,后面学会了补上)