动态规划:暴力递归如何变优雅?
斐波那契数列用纯递归算 fib(50),宇宙毁灭都算不完;加一行"记忆化",瞬间完成。这就是动态规划(DP)的魔力:把指数级暴力变成多项式级优雅。今天用最经典的例子讲透 DP 的思维框架。
一、先看暴力递归的代价
python
def fib(n):
if n <= 1: return n
return fib(n-1) + fib(n-2) # 重复计算!
fib(5) 要算 fib(4)+fib(3),fib(4) 又要算 fib(3)+fib(2)------同一个子问题被反复计算,调用树呈指数级膨胀:
fib(20) 纯递归调用次数: 21,891 次
fib(30): 约 270 万次
fib(50): 约 200 亿亿次(算不完)
二、DP 的核心洞察:记住算过的
观察发现子问题大量重复(fib(3) 被算了 N 次)。解法朴素得惊人------算过就存下来(记忆化):
python
memo = {}
def fib_memo(n):
if n <= 1: return n
if n not in memo:
memo[n] = fib_memo(n-1) + fib_memo(n-2)
return memo[n]
每个子问题只算一次 → 调用次数从指数级降到线性。
三、DP 的思维框架:四步法
- 定义状态:dpi 表示什么?(如"第 i 个斐波那契数")
- 找转移方程:dpi 怎么由更小的状态推出?(dpi = dpi-1+dpi-2)
- 确定初始条件:dp0、dp1 是什么?
- 决定计算顺序:自顶向下(记忆化递归)或自底向上(迭代填表)
自底向上版:
python
def fib_dp(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]
四、代码演示:561 倍的差距
python
counts = {"recur": 0, "memo": 0}
def fib_recur(n):
counts["recur"] += 1
if n <= 1: return n
return fib_recur(n-1) + fib_recur(n-2)
memo = {}
def fib_memo(n):
counts["memo"] += 1
if n <= 1: return n
if n not in memo:
memo[n] = fib_memo(n-1) + fib_memo(n-2)
return memo[n]
fib_recur(20)
fib_memo(20)
print(f"fib(20) 纯递归调用次数: {counts['recur']:,}")
print(f"fib(20) 记忆化调用次数: {counts['memo']}")
print(f"加速: {counts['recur']/counts['memo']:.0f} 倍(指数级 -> 线性)")
运行输出:
fib(20) 纯递归调用次数: 21,891
fib(20) 记忆化调用次数: 39
加速: 561 倍(指数级 -> 线性)
同一个 fib(20),纯递归算了 21891 次,记忆化只算 39 次------561 倍差距,n 越大差距越恐怖。这就是"记住算过的"的威力。
五、避坑清单
- 先想清楚状态定义再写码:状态定义错了,转移方程全是错的
- 区分记忆化递归和迭代 DP:前者自顶向下(适合思路直观),后者自底向上(无递归栈开销)
- 别急着优化空间:先写对(二维 dp 表),再谈滚动数组优化
- DP 不只看一维:背包是二维、区间 DP 按长度枚举、状压 DP 用位表示集合
- "最优子结构 + 重叠子问题"是 DP 的适用条件:不具备就别硬套(贪心/分治可能更合适)
六、想系统学算法?
本文精选自 ima 知识号【Kruptos】《数据结构与算法详解》订阅库(第 088 期动态规划入门状态与转移、第 090 期区间 DP 与 LIS 等 100 期系统教程,从数组、链表、树到排序、递归分治、动态规划、图论,每期配可运行代码)。
📚 完整系列 100 期 + 配套代码,已在 ima 知识号发布
本文只是系列的一个切片。完整系列(100 期系统教程 + 每期可运行代码)在 ima 知识号【Kruptos】持续更新中:
- 🗂 68+ 技术知识库:信号与系统、SDR 软件无线电、数字信号处理、操作系统、AI Agent、大模型微调......几乎覆盖全部软硬件技术栈
- 🧠 8 款 AI 技能:系列生产、知识库管理、CMMI 受管开发、自进化 Agent 等,已在 ima 技能广场上架,即装即用
- ✅ 全部免费订阅,后续更新自动推送
🔍 订阅方式:打开 ima(腾讯智能工作台)→ 搜索「Kruptos」→ 一键订阅。或在 ima 内直接搜索《数据结构与算法详解》等知识库名称。
💬 你面试遇到最难的 DP 题是哪道?评论区聊聊------想看背包问题还是 LIS,点赞高的安排。
作者:Kruptos(西电毕业,13 年无线通信/DSP/嵌入式科研)|原创内容,转载注明出处