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 个泰波那契数字的数组。