• 力扣之斐波那契数列



    本来以为就是非常简单的一道题,想着递归大法来着,结果n=37时直接超过时间限制了o(╥﹏╥)o

    题目

    在这里插入图片描述
    在这里插入图片描述

    解法

    一、动态规划法

    • 滚动数组思想
    class Solution:
        def fib(self, n: int) -> int:
            MOD = 10 ** 9 + 7
            if n < 2:
                return n
            p, q, r = 0, 0, 1
            for i in range(2, n + 1):
                p = q
                q = r
                r = (p + q) % MOD
            return r
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 该方法时间复杂度是 O ( n ) O(n) O(n),但空间复杂度是 O ( 1 ) O(1) O(1)

    二、矩阵法

    • 发现 F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n)=F(n-1)+F(n-2) F(n)=F(n1)+F(n2)可以用矩阵表示成
    • [ 1 1 1 0 ] [ F ( n ) F ( n − 1 ) ] = [ F ( n ) + F ( n − 1 ) F ( n ) ] = [ F ( n + 1 ) F ( n ) ] \left[
      1110" role="presentation" style="position: relative;">1110
      \right]\left[
      F(n)F(n1)" role="presentation" style="position: relative;">F(n)F(n1)
      \right]=\left[
      F(n)+F(n1)F(n)" role="presentation" style="position: relative;">F(n)+F(n1)F(n)
      \right]=\left[
      F(n+1)F(n)" role="presentation" style="position: relative;">F(n+1)F(n)
      \right]
      [1110][F(n)F(n1)]=[F(n)+F(n1)F(n)]=[F(n+1)F(n)]
    • [ F ( n + 1 ) F ( n ) ] = [ 1 1 1 0 ] n [ F ( 1 ) F ( 0 ) ] \left[
      F(n+1)F(n)" role="presentation" style="position: relative;">F(n+1)F(n)
      \right]=\left[
      1110" role="presentation" style="position: relative;">1110
      \right]^{n}\left[
      F(1)F(0)" role="presentation" style="position: relative;">F(1)F(0)
      \right]
      [F(n+1)F(n)]=[1110]n[F(1)F(0)]
    • M = [ 1 1 1 0 ] M=\left[
      1110" role="presentation" style="position: relative;">1110
      \right]
      M=[1110]
    • 然后这里的问题就转化成了快速求矩阵乘积,我看官方的方法好像也就是普通的行×列这样的,得自己写个函数
    • 函数1: 2 × 2 2\times 2 2×2矩阵乘法
    • 函数2:求矩阵的n次方
    • 哦哦哦!!我才懂,原来奥秘在算 M n M^n Mn的时候,不要一个一个的乘,如果n是偶数,比如说8这种,那我只要计算 M 2 → M 4 → M 8 M^2\rightarrow M^4\rightarrow M^8 M2M4M8即可,也就是 log ⁡ 2 8 = 3 \log_2 8=3 log28=3次即可

    代码

    class Solution:
        def fib(self, n: int) -> int:
            MOD = 10 ** 9 + 7
            if n < 2:
                return n
    
            def multiply(a: List[List[int]], b: List[List[int]]) -> List[List[int]]:
                c = [[0, 0], [0, 0]]
                for i in range(2):
                    for j in range(2):
                        c[i][j] = (a[i][0] * b[0][j] + a[i][1] * b[1][j]) % MOD
                return c
    
            def matrix_pow(a: List[List[int]], n: int) -> List[List[int]]:
                ret = [[1, 0], [0, 1]]
                while n > 0:
                    if n & 1:
                        ret = multiply(ret, a)
                    n >>= 1
                    a = multiply(a, a)
                return ret
    
            res = matrix_pow([[1, 1], [1, 0]], n - 1)
            return res[0][0]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    -这个 n >>= 1位运算,之前没见过,开了篇博客一起学习一下(位运算与集合运算

    • 话说这个n&1 = 1也是位运算,就是判断n奇偶性的,等价于n%2 =1
    • 时间复杂度是 O ( log ⁡ n ) O(\log n) O(logn),空间复杂度是 O ( 1 ) O(1) O(1)

    三、递归法

    • 原理: 把 f ( n ) f(n) f(n) 问题的计算拆分成 f ( n − 1 ) f(n−1) f(n1) f ( n − 2 ) f(n-2) f(n2) 两个子问题的计算,并递归,以 f ( 0 ) f(0) f(0) f ( 1 ) f(1) f(1) 为终止条件。
    • 缺点: 大量重复的递归计算,例如 f ( n ) f(n) f(n) f ( n − 1 ) f(n - 1) f(n1)两者向下递归需要 各自计算 f ( n − 2 ) f(n−2) f(n2) 的值。
      • !!是的!!现在才反应过来,单独算确实有很多重复计算
        在这里插入图片描述
  • 相关阅读:
    受心理学启发,这项眼球追踪生成式模型大幅降低训练成本
    Spring Cloud Sleuth介绍
    全国青少年编程等级考试python一级真题2021年12月(含题库答题软件账号)
    敢不敢和佳信文本机器人PK,你和它哪个更高情商~
    STL容器之list
    pandas(进阶操作)-- 处理非数值型数据 -- 数据分析三剑客(核心)
    10. Java异常(Exception)
    Docker 使用原理流程
    【小5聊】纯javascript实现图片放大镜效果
    回文串算法题解
  • 原文地址:https://blog.csdn.net/universe_1207/article/details/126530283