元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
算法基础
▶
复杂度分析
时间复杂度
空间复杂度
渐进符号
▶
算法思想
分治法
贪心算法
回溯法
概率算法
枚举算法
递推算法
递归算法
动态规划
分支限界法
模拟算法
▶
算法分析
正确性证明
性能优化
算法比较
▶
搜索算法
▶
基本搜索
顺序搜索
二分搜索
插值搜索
▶
图搜索
深度优先搜索
广度优先搜索
启发式搜索
▶
高级搜索
双向搜索
A*算法
模式匹配
▶
排序算法
▶
比较类排序
冒泡排序
快速排序
归并排序
插入排序
选择排序
▶
非比较类排序
计数排序
基数排序
桶排序
▶
高级排序
堆排序
希尔排序
外部排序
拓扑排序
▶
图论算法
▶
图的表示
邻接矩阵
邻接表
边集数组
▶
最短路径
Dijkstra算法
Floyd算法
Bellman-Ford算法
最短路径概述
▶
生成树
Prim算法
Kruskal算法
并查集
最小生成树
▶
图的连通性
强连通分量
割点与桥
双连通分量
欧拉路径
▶
动态规划
▶
基础概念
最优子结构
重叠子问题
状态转移方程
▶
经典问题
背包问题
最长公共子序列
编辑距离
▶
优化技巧
空间优化
状态压缩
区间动态规划
▶
字符串算法
▶
字符串匹配
KMP算法
Boyer-Moore算法
Sunday算法
▶
字符串处理
字典树
后缀数组
字符串哈希
▶
压缩算法
游程编码
Huffman编码
LZ77算法
发布时间:
2025-03-21 19:48
↑
☰
# 重叠子问题 重叠子问题是动态规划的另一个重要特征,它指的是在递归过程中,相同的子问题被重复计算多次。识别和处理重叠子问题是优化算法效率的关键。 ## 基本概念 ### 定义 重叠子问题具有以下特点: - 同一个子问题在递归树中出现多次 - 这些子问题的解是相同的 - 可以通过记忆化或表格法避免重复计算 ### 示例说明 以斐波那契数列为例: - F(n) = F(n-1) + F(n-2) - 计算F(5)时,F(3)会被重复计算 - F(3)在计算F(5)和F(4)时都会用到 ## 识别重叠子问题 ### 关键特征 1. 递归调用 - 存在重复的函数调用 - 参数相同的调用会得到相同结果 2. 重复计算 - 相同的子问题被多次求解 - 造成不必要的计算开销 3. 优化空间 - 可以通过缓存优化 - 避免重复计算提高效率 ## 解决方案 ### 记忆化搜索 ```go // 斐波那契数列的记忆化实现 func fibMemo(n int, memo map[int]int) int { // 检查是否已经计算过 if val, exists := memo[n]; exists { return val } // 基本情况 if n <= 1 { return n } // 计算并存储结果 memo[n] = fibMemo(n-1, memo) + fibMemo(n-2, memo) return memo[n] } // 封装函数 func fibonacci(n int) int { memo := make(map[int]int) return fibMemo(n, memo) } ``` ### 动态规划表格法 ```go // 斐波那契数列的动态规划实现 func fibDP(n int) int { if n <= 1 { return n } // 创建DP表格 dp := make([]int, n+1) dp[0], dp[1] = 0, 1 // 填充表格 for i := 2; i <= n; i++ { dp[i] = dp[i-1] + dp[i-2] } return dp[n] } ``` ## 优化技巧 ### 空间优化 1. 状态压缩 - 只保存必要的状态 - 使用滚动数组 ```go // 空间优化的斐波那契数列实现 func fibOptimized(n int) int { if n <= 1 { return n } prev, curr := 0, 1 for i := 2; i <= n; i++ { prev, curr = curr, prev+curr } return curr } ``` ### 查找表优化 1. 哈希表 - 快速查找已计算结果 - 适合离散的状态空间 2. 数组 - 适合连续的状态空间 - 访问速度更快 ## 实际应用 ### 经典问题 1. 背包问题 - 重复计算相同重量的子问题 - 使用DP表格避免重复 2. 最长公共子序列 - 重复计算相同前缀的子问题 - 使用二维DP表格优化 ### 性能对比 1. 递归实现 - 时间复杂度:O(2^n) - 空间复杂度:O(n) - 存在大量重复计算 2. 记忆化实现 - 时间复杂度:O(n) - 空间复杂度:O(n) - 避免重复计算 3. 动态规划实现 - 时间复杂度:O(n) - 空间复杂度:O(n) - 自底向上构建解 ## 设计建议 ### 实现策略 1. 递归到记忆化 - 先写递归版本 - 添加记忆化优化 - 分析重复子问题 2. 记忆化到DP - 观察计算顺序 - 设计状态转移 - 优化空间使用 ### 注意事项 1. 状态设计 - 选择合适的状态表示 - 避免状态过多 2. 边界处理 - 正确处理基本情况 - 注意特殊输入 3. 优化方向 - 考虑空间优化 - 分析是否需要记忆化 ## 总结 1. 重要性 - 影响算法效率 - 优化的关键点 - 设计DP的基础 2. 解决方法 - 记忆化搜索 - 动态规划表格 - 空间优化技巧 3. 实践建议 - 从简单问题开始 - 逐步优化实现 - 注意时空权衡