力扣之斐波那契数列


本来以为就是非常简单的一道题,想着递归大法来着,结果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

  • 该方法时间复杂度是 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[\begin{array}{ll} 1 & 1 \\ 1 & 0 \end{array}\right]\left[\begin{array}{c} F(n) \\ F(n-1) \end{array}\right]=\left[\begin{array}{c} F(n)+F(n-1) \\ F(n) \end{array}\right]=\left[\begin{array}{c} F(n+1) \\ F(n) \end{array}\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[\begin{array}{c} F(n+1) \\ F(n) \end{array}\right]=\left[\begin{array}{ll} 1 & 1 \\ 1 & 0 \end{array}\right]^{n}\left[\begin{array}{l} F(1) \\ F(0) \end{array}\right] [F(n+1)F(n)]=[1110]n[F(1)F(0)]
  • M = [ 1 1 1 0 ] M=\left[\begin{array}{ll} 1 & 1 \\ 1 & 0 \end{array}\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]

-这个 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) 的值。
    • !!是的!!现在才反应过来,单独算确实有很多重复计算
      在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

universe_1207

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值