LeetCode 剑指Offer 10- I 斐波那契数列

LeetCode 剑指Offer 10- I 斐波那契数列

题目

在这里插入图片描述

解题

以下题目解题方法相同,区别点是根据题干,动态转移方程会有差异。

题目解题
面试题 08.01. 三步问题三步问题题解
剑指 Offer 10- I. 斐波那契数列斐波那契数列题解
70. 爬楼梯爬楼梯
剑指Offer 10- II 青蛙跳台阶问题青蛙跳台阶问题

解题一:动态规划

在这里插入图片描述

// javascript
var fib = function(n) {
    if (n < 2) return n;
    const MOD = 1e9 + 7;
    let p = 0, q = 1, r;
    for (let i = 2; i <= n; ++i) {
        r = (p + q) % MOD;
        p = q;
        q = r;
    }
    return r;
};

在这里插入图片描述
自上而下的记忆化搜索:

// javascript
var fib = function(n) {
    const MOD = 1e9 + 7;
    const record = new Map();
    record.set(0, 0);
    record.set(1, 1);
    const findFib = (n) => {
        if (record.has(n) === false) {
            const val = (findFib(n - 1) + findFib(n - 2)) % MOD;
            record.set(n, val);
        }
        return record.get(n);
    };
    return findFib(n);
};

空间复杂度: O ( n ) O(n) O(n),递归 + 记录结果的哈希表的额外空间。

解题二:矩阵快速幂

在这里插入图片描述
[ F ( n ) F ( n − 1 ) ] = [ 1 1 0 1 ] n − 1 ∗ [ F ( 1 ) F ( 0 ) ] , 令 A = [ a b c d ] = [ 1 1 0 1 ] n − 1 \begin{bmatrix} F(n) \\ F(n-1) \end{bmatrix} = {\begin{bmatrix} 1 & 1 \\ 0 & 1\end{bmatrix}}^{n-1} * \begin{bmatrix} F(1) \\ F(0) \end{bmatrix}, 令 A = \begin{bmatrix} a & b \\ c & d \end{bmatrix} = {\begin{bmatrix} 1 & 1 \\ 0 & 1\end{bmatrix}}^{n-1} [F(n)F(n1)]=[1011]n1[F(1)F(0)],A=[acbd]=[1011]n1

[ F ( n ) F ( n − 1 ) ] = [ a b c d ] ∗ [ F ( 1 ) F ( 0 ) ] = [ a b c d ] ∗ [ 1 0 ] = [ a c ] \begin{bmatrix} F(n) \\ F(n-1) \end{bmatrix} = \begin{bmatrix} a & b \\ c & d \end{bmatrix} * \begin{bmatrix} F(1) \\ F(0) \end{bmatrix} = \begin{bmatrix} a & b \\ c & d \end{bmatrix} * \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} a \\ c \end{bmatrix} [F(n)F(n1)]=[acbd][F(1)F(0)]=[acbd][10]=[ac]

因此 F ( n ) = a = A [ 0 ] [ 0 ] F(n) = a = A[0][0] F(n)=a=A[0][0]

注意要使用 BigInt 类型。

// javascript
var fib = function(n) {
    if (n < 2) return n;
    const q = [[1, 1], [1, 0]];
    const res = matpow(q, n - 1);
    return res[0][0];
};

// const matpow = (a, n) => {
//     if (n === 1) return a;
//     const b = matpow(a, n >> 1);
//     let res = matmul(b, b);
//     if (n % 2 === 1) {
//         res = matmul(res, a);
//     }
//     return res;
// };

const matpow = (a, n) => {
    let ret = [[1, 0], [0, 1]];
    // 以 7 (0b111) 为例,a^7 = a^4 + a^2 + a^1
    while (n > 0) {
        if ((n & 1) === 1) {
            ret = matmul(ret, a);
        }
        n >>= 1;
        a = matmul(a, a);
    }
    return ret;
};

const matmul = (a, b) => {
    const m1 = a.length, n1 = a[0].length;
    const m2 = b.length, n2 = b[0].length;
    if (n1 !== m2) {
        throw new Error('these 2 matrix can not be multiplied!');
    }
    // 初始化时要用 BigInt 类型 => 数字后面加 n
    const res = new Array(m1).fill(0n).map(() => new Array(n2).fill(0n));
    for (let i = 0; i < m1; ++i) {
        for (let j = 0; j < n2; ++ j) {
            for (let k = 0; k < n1; ++k) {
                res[i][j] += BigInt(a[i][k]) * BigInt(b[k][j]); 
            }
            // 结果取模
            res[i][j] %= BigInt(1e9 + 7);
        }
    }
    return res;
};

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值