509. 斐波那契数

方法一:递归

class Solution:
    def fib(self, n: int) -> int:
        if n in [0,1]: return n
        return self.fib(n-1) + self.fib(n-2)

方法二:动态规划

class Solution:
    def fib(self, n: int) -> int:
        if n in [0,1]: return n
        x, y = 0, 1
        for i in range(2,n+1):
            x, y = y, x+y
        return y

方法三:预计算

class Solution:
    def __init__(self):
        m = 31
        self.dp = dp = [0]*m
        dp[0]=0
        dp[1]=dp[2]=1
        for i in range(3,m):
            dp[i] = dp[i-1]+dp[i-2]

    def fib(self, n: int) -> int:
        return self.dp[n]

1137. 第 N 个泰波那契数

首先介绍性能优化

已知 n 小于 38,可以先将 Tribonacci 数列的前 38 项计算出来,保存在一个静态数组中。每次执行测试用例时,直接检索对应数字即可。

如何计算 Tribonacci 数列?

两种方法:带记忆的递归和动态计算。这两种方法计算 N 个 Tribonacci 数列都需要 N 步操作。类似 tribonacci(k) = tribonacci(k - 1) + tribonacci(k - 2) + tribonacci(k - 3) 这种简单递归不在讨论之列,因为这种递归方法的复杂度达到 3^N3
N。

初步计算所有 Tribonacci 数保存在静态数组的方法,运行时性能为 O(1),但是需要 O(N) 的空间记录 N 个斐波那契数。在保证性能的同时优化空间也非常重要。

在不允许占用大量空间的情况下,可以使用动态计算的方法,在内存中保留不超过 3 个斐波那契数即可。

方法一:空间优化:动态计算

class Solution:
    def tribonacci(self, n: int) -> int:
        if n < 3:  return 1 if n else 0        
        x, y, z = 0, 1, 1
        for _ in range(n - 2):
            x, y, z = y, z, x + y + z
        return z

复杂度分析
时间复杂度:O(N)。
空间复杂度:O(1),保存最后 3 个斐波那契数。

方法二:性能优化:带记忆的递归

预计算 38 个 Tribonacci 数
从预计算的数组中检索所需的泰波那契数。

class Solution:
    def __init__(self):
        def h(k):
            if k == 0:        return 0            
            if dp[k]:return dp[k]
            dp[k] = h(k-1) + h(k-2) + h(k-3) 
            return dp[k]
        
        n = 38
        self.dp = dp = [0] * n
        dp[1] = dp[2] = 1
        h(n-1)
    
    def tribonacci(self, n: int) -> int:
        return self.dp[n]

复杂度分析

时间复杂度:O(1),预计算 38 个 Tribonacci 数,并在数组中检索。
空间复杂度:O(1),存储 38 个 Tribonacci 数的数组。

方法三:性能优化:动态计算

预计算 38 个泰波那契数:

初始化一个数组用于保存泰波那契数,并初始化前 3 个泰波那契数字。

i 从 3 循环到 38,每一步计算出一个新的泰波那契数:nums[i] = helper(i - 1) + helper(i - 2) + helper(i - 3)。

从数组中检索所需的泰波那契数。

class Solution:
    def __init__(self):
        n = 38
        self.nums = nums = [0] * n
        nums[1] = nums[2] = 1
        for i in range(3, n):
            nums[i] = nums[i-1] + nums[i-2] + nums[i-3]
    
    def tribonacci(self, n: int) -> int:
        return self.nums[n]

复杂度分析

时间复杂度:\mathcal{O}(1)O(1),预计算 38 个泰波那契数字,并在数组中检索。
空间复杂度:\mathcal{O}(1)O(1),存储 38 个泰波那契数字的数组。