斐波那契数列:你真的懂Fibonacci sequence吗? - 图1
斐波那契数列递推关系式如下:
你真的懂Fibonacci sequence吗? - 图2

题目:求解斐波那契数列第n项?**

1. 递归方法

  1. def Fibonacci(n):
  2. if n == 0 or n == 1:
  3. return n
  4. else:
  5. return Fibonacci(n-1) + Fibonacci(n-2)

通过画出递归树,上述代码存在大量重复的操作。
例如,计算你真的懂Fibonacci sequence吗? - 图3你真的懂Fibonacci sequence吗? - 图4
可以看到你真的懂Fibonacci sequence吗? - 图5重复计算了。

2. 递归方法优化

如何减少重复计算呢?这里跟动态规划中剪枝的思想类似,构建一个DPTable,存储已计算过的项,达到利用空间换时间。

  1. def Fibonacci(n):
  2. if n == 0 or n == 1:
  3. return n
  4. dp = [0] * (n+1) # 构造有n个元素的列表,存储已计算过的项
  5. dp[1] = 1
  6. for i in range(2, n+1):
  7. dp[i] = dp[i-1] + dp[i-2]
  8. return dp[i]

时间复杂度:你真的懂Fibonacci sequence吗? - 图6,空间复杂度你真的懂Fibonacci sequence吗? - 图7

3. 分治策略

斐波那契数列是二阶递推数列,存在一个你真的懂Fibonacci sequence吗? - 图8的矩阵你真的懂Fibonacci sequence吗? - 图9,使得:
你真的懂Fibonacci sequence吗? - 图10
求解可得:
你真的懂Fibonacci sequence吗? - 图11

你真的懂Fibonacci sequence吗? - 图12

接下来就是求解你真的懂Fibonacci sequence吗? - 图13
指数的幂次方直接计算需要计算你真的懂Fibonacci sequence吗? - 图14次乘法,通过二分法来求解,只需要计算你真的懂Fibonacci sequence吗? - 图15

  1. def metric_product(x, base):
  2. a = x[0][0]*base[0][0] + x[0][1]*base[1][0]
  3. b = x[0][0]*base[0][1] + x[0][1]*base[1][1]
  4. c = x[1][0]*base[0][0] + x[1][1]*base[1][0]
  5. d = x[1][0]*base[0][1] + x[1][1]*base[1][1]
  6. return [[a, b], [c, d]]
  7. def fib(self, n: int) -> int:
  8. if n == 0:
  9. return 0
  10. def metric(n):
  11. base = [[1, 1], [1, 0]]
  12. # 求 pow(base, n)
  13. if n == 1:
  14. return base
  15. elif n % 2 == 0:
  16. half = metric(n//2)
  17. return metric_product(half, half)
  18. else:
  19. half = metric(n//2)
  20. return metric_product(metric_product(half, half), base)
  21. ans = metric(n)
  22. f_n = ans[0][1]
  23. return f_n

4. 动态规划

为了减少空间复杂度

  1. def fib(n):
  2. a, b = 0, 1
  3. for _ in range(n):
  4. a, b = b, a + b
  5. return a

时间复杂度你真的懂Fibonacci sequence吗? - 图16, 空间复杂度你真的懂Fibonacci sequence吗? - 图17

5. 求第n项关于10007的余数

image.png
利用余数的性质3,简化最后直接求出f(n)再算余数的复杂,同时也保证了数值不溢出。虽然python支持大数,这个方法也适用于其他语言。

  1. def fab(n):
  2. a, b = 1, 1
  3. for _ in range(2, n):
  4. b, a = (a+b) % 10007, b % 10007
  5. return b
  6. n = int(input())
  7. ans = fab(n)
  8. print(ans % 10007)