返回

刷题挑战:LeetCode 509 斐波那契数,巧解路径依赖

见解分享

对于新手程序员来说,LeetCode 509 斐波那契数是一道经典算法题,它考验对递归和动态规划等概念的理解。而本文将深入浅出地介绍一种巧妙的路径依赖解法,帮助读者轻松攻克这道难题。

斐波那契数列

斐波那契数列是以意大利数学家莱昂纳多·斐波那契(Leonardo Fibonacci)的名字命名的。该数列从 0 和 1 开始,后面的每一项数字都是前面两项数字的和。前几项数字如下:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...

递归解法

LeetCode 509 斐波那契数的题目要求我们计算第 n 个斐波那契数。最直接的想法是使用递归来解决这个问题。递归函数的定义如下:

fib(n) = {
    0,                              if n = 0
    1,                              if n = 1
    fib(n-1) + fib(n-2),            otherwise
}

这种解法虽然简单直观,但存在一个致命的问题:它会产生大量的重复计算。例如,计算 fib(5) 时,需要计算 fib(4) 和 fib(3);计算 fib(4) 时,又需要计算 fib(3) 和 fib(2);而计算 fib(3) 时,又需要计算 fib(2) 和 fib(1)。如此下去,就会产生大量重复的计算,导致程序运行速度非常慢。

动态规划解法

为了解决这个问题,我们可以使用动态规划来优化递归解法。动态规划是一种自底向上的解决问题的方法,它将问题的解存储在一个表格中,以便以后可以重复使用。对于斐波那契数列,我们可以创建一个表格 dp,其中 dp[n] 表示第 n 个斐波那契数。

动态规划解法的步骤如下:

  1. 初始化 dp[0]dp[1],分别为 0 和 1。
  2. 对于 i 从 2 到 n,计算 dp[i] = dp[i-1] + dp[i-2]
  3. 返回 dp[n].

这种解法的时间复杂度为 O(n),比递归解法快得多。

路径依赖解法

以上两种解法都是比较常见的解法,本文要介绍的路径依赖解法是一种更为巧妙的解法。路径依赖解法的主要思想是:对于第 n 个斐波那契数,它可以表示为第 n-1 个斐波那契数和第 n-2 个斐波那契数的和。而第 n-1 个斐波那契数又可以表示为第 n-2 个斐波那契数和第 n-3 个斐波那契数的和,以此类推。

因此,我们可以使用一个辅助函数 fib_path 来计算第 n 个斐波那契数。fib_path 函数的定义如下:

fib_path(n, path) = {
    0,                              if n = 0
    1,                              if n = 1
    fib_path(n-1, path + "->" + str(n-1)) + fib_path(n-2, path + "->" + str(n-2)),  otherwise
}

其中,path 表示从 0 到 n 的路径,例如,fib_path(5, "") 的值为 "0->1->1->2->3->5"

我们可以使用 fib_path 函数来计算第 n 个斐波那契数,然后从 path 中提取出从 0 到 n 的路径。

fib = fib_path(n, "")
path = path.split("->")
print("第", n, "个斐波那契数为", fib)
print("从 0 到", n, "的路径为:", path)

这种解法的时间复杂度为 O(n),与动态规划解法相同,但它具有以下几个优点:

  • 代码更加简洁优雅。
  • 可以方便地提取出从 0 到 n 的路径。
  • 可以扩展到计算斐波那契数列的任意一段。

总结

本文介绍了三种解法:递归解法、动态规划解法和路径依赖解法。这三种解法各有优缺点,读者可以根据自己的实际情况选择合适的解法。