LeetCode 509:斐波那契数

题意:

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n)

示例:

示例1:

**输入:**n = 2
**输出:**1
**解释:**F(2) = F(1) + F(0) = 1 + 0 = 1

示例2:

**输入:**n = 3
**输出:**2
**解释:**F(3) = F(2) + F(1) = 1 + 1 = 2

示例3:

**输入:**n = 4
**输出:**3
**解释:**F(4) = F(3) + F(2) = 2 + 1 = 3

提示:

  • 0 <= n <= 30

我的解法:

思路:

1.创建一个fn_list列表,用于保存从f0,f1,…,fn,并将f0 = 0, f1 = 1存入列表。

  1. 如果n≤1,返回 fn_list的第n项;
如果n>1,根据公式F(n) = F(n - 1) + F(n - 2),依次求出f2,…,fn-1,并存入fn_list。返回fn_list[n-1] + fn_list[n-2]。
class Solution:
    def fib(self, n: int) -> int:
        fn_list = [0,1]
        #判断n是否大于1
        if n <= 1:
            return fn_list[n]
        #当n大于1时
        i = 2
        while i < n:
            f = fn_list[i-1] + fn_list[i-2] 
            fn_list.append(f)
            i += 1
        return fn_list[n-1] + fn_list[n-2]

分析:

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。
提交结果执行时间内存消耗
通过40 ms14.8 MB

2.注意:不要漏掉n≤1的情况。

官方解法

### 方法一:动态规划**滑动窗口**

#### 思路:

斐波那契数的边界条件是 F(0)=0 和 F(1)=1。当 n>1时,每一项的和都等于前两项的和,因此有如下递推关系:

F(n)=F(n-1)+F(n-2)

由于斐波那契数存在递推关系,因此可以使用动态规划求解。动态规划的状态转移方程即为上述递推关系,边界条件为 F(0) 和 F(1)。

根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n) 的实现。由于 F(n) 只和 F(n-1)与 F(n-2) 有关,因此可以使用「滚动数组思想」把空间复杂度优化成 O(1)。如下的代码中给出的就是这种实现。
class Solution:
    def fib(self, n: int) -> int:
        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
        
        return r

#### 复杂度分析

- 时间复杂度:O(n)。
- 空间复杂度:O(1)。

执行用时:40 ms;内存消耗:14.8 MB。

### 方法二:矩阵快速幂

方法一的时间复杂度是 O(n)。使用矩阵快速幂的方法可以降低时间复杂度。

首先我们可以构建这样一个递推关系:

[ 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}{c}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]

因此只要我们能快速计算矩阵 M 的 n 次幂,就可以得到 F(n) 的值。如果直接求取 M^n,时间复杂度是 O(n),可以定义矩阵乘法,然后用快速幂算法来加速这里 M^n的求取。
class Solution:
    def fib(self, n: int) -> int:
        if n < 2:
            return n
        
        q = [[1, 1], [1, 0]]
        res = self.matrix_pow(q, n - 1)
        return res[0][0]
    
    def matrix_pow(self, a: List[List[int]], n: int) -> List[List[int]]:
        ret = [[1, 0], [0, 1]]
        while n > 0:
            if n & 1:
                ret = self.matrix_multiply(ret, a)
            n >>= 1
            a = self.matrix_multiply(a, a)
        return ret

    def matrix_multiply(self, 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]
        return c

#### 复杂度分析:

- 时间复杂度:O(logn)。
- 空间复杂度:O(1)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值