刷题挑战:LeetCode 509 斐波那契数,巧解路径依赖
2024-02-13 14:50:08
对于新手程序员来说,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
个斐波那契数。
动态规划解法的步骤如下:
- 初始化
dp[0]
和dp[1]
,分别为 0 和 1。 - 对于
i
从 2 到n
,计算dp[i] = dp[i-1] + dp[i-2]
。 - 返回
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 的路径。
- 可以扩展到计算斐波那契数列的任意一段。
总结
本文介绍了三种解法:递归解法、动态规划解法和路径依赖解法。这三种解法各有优缺点,读者可以根据自己的实际情况选择合适的解法。