1. 动态规划入门:从斐波那契数列说起
第一次接触动态规划时,很多人都会被这个高大上的名字吓到。其实它的核心思想非常简单——把大问题拆解成小问题,并且记住已经解决过的小问题答案。就像我们小时候背乘法口诀表一样,记住"三七二十一"之后,下次就不用再重新计算了。
斐波那契数列是最经典的动态规划案例。这个数列的特点是:每个数字都是前两个数字之和。用代码表示就是:
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
这个递归解法虽然直观,但效率极低。比如计算fib(5)时,会重复计算fib(3)两次、fib(2)三次。当n变大时,这种重复计算会呈指数级增长。
动态规划的精妙之处就在于它解决了这个问题。我们可以用一个数组来存储已经计算过的结果:
def fib(n):
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
这样就把时间复杂度从O(2^n)降到了O(n)。我第一次用这个方法时,感觉就像发现了新大陆——原来算法优化可以这么简单直接!
2. 爬楼梯问题:斐波那契的变种
LeetCode第70题"爬楼梯"是斐波那契数列的完美变种。题目说:假设你正在爬楼梯,每次可以爬1或2个台阶,问有多少种不同的方法可以爬到第n阶。
我第一次做这题时,尝试用枚举法列出了前几项:
- 1阶:1种(1)
- 2阶:2种(1+1,2)
- 3阶:3种(1+1+1,1+2,2+1)
- 4阶:5种...
突然发现这不就是斐波那契数列吗?因为要到达第n阶,要么从n-1阶跨1步上来,要么从n-2阶跨2步上来。所以状态转移方程就是:
dp[n] = dp[n-1] + dp[n-2]
这个发现让我兴奋不已。原来很多看似不同的问题,背后可能是同一个数学模型。代码实现几乎和斐波那契数列一样:
def climbStairs(n):
if n <= 2:
return n
a, b = 1, 2
for _ in range(3, n+1):
a, b = b, a + b
return b
这里我用了空间优化的写法,只保留前两

1199

被折叠的 条评论
为什么被折叠?



