动态规划专题一

184 阅读2分钟

这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战 | 创作学习持续成长,夺宝闯关赢大奖 - 掘金 (juejin.cn)

题目链接

  1. 斐波那契数列 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题解的图

10_I_fig1.gif

斐波那契数列只关心最后两个数的相加和,因此可以用到滚动数组的思想
解法很直白,不做太多解释:

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
}

(很抱歉不是科班出身,实在看不懂矩阵幂的解法,后面学会了补上)