动态规划算法
动态规划
code: dynamic_programming
1. 问题分析
1.1 问题定义
问题:假设要爬n阶楼梯,每次可以爬1阶或2阶,问有多少种不同的方法可以爬到楼顶。
示例:
- n=1:只有1种方法(1)
- n=2:有2种方法(1+1, 2)
- n=3:有3种方法(1+1+1, 1+2, 2+1)
1.2 数学递推关系
1 | dp[n] = dp[n-1] + dp[n-2] |
解释:到达第n阶楼梯,可以从第n-1阶爬1阶上来,或者从第n-2阶爬2阶上来。
2. 各算法实现详细解析
2.1 暴力递归算法 (ViolentRecursion)
1 | int32_t ViolentRecursion::ClimbStairs(uint32_t stairFloors) |
算法思想:直接根据递推公式进行递归计算。
时间复杂度分析:
- 形成二叉树递归结构,高度为n
- 时间复杂度:O(2^n) - 指数级复杂度
- 空间复杂度:O(n) - 递归栈深度
缺点:存在大量重复计算。例如计算ClimbStairs(5)时:
ClimbStairs(3)被计算了2次ClimbStairs(2)被计算了3次ClimbStairs(1)被计算了5次
2.2 记忆化搜索算法 (MemoryBasedSearch)
1 | int32_t MemoryBasedSearch::ClimbStairs(uint32_t stairFloors) |
算法思想:在递归基础上增加记忆化,避免重复计算。
时间复杂度:O(n) - 每个子问题只计算一次
空间复杂度:O(n) - 存储n个结果+递归栈深度
2.3 标准动态规划算法 (DynamicProgramming)
1 | int32_t DynamicProgramming::ClimbStairs(uint32_t stairFloors) |
算法思想:自底向上构建解,从基础情况逐步推导到目标解。
动态规划三要素:
- 最优子结构:大问题的最优解包含小问题的最优解
- 重叠子问题:问题可以分解为重复的子问题
- 状态转移方程:
dp[i] = dp[i-1] + dp[i-2]
时间复杂度:O(n)
空间复杂度:O(n)
2.4 空间优化版动态规划 (PerfDynamicProgramming)
1 | int32_t PerfDynamicProgramming::ClimbStairs(uint32_t stairFloors) |
优化思想:观察状态转移方程发现,当前状态只依赖于前两个状态,因此不需要存储整个数组。
为什么prev2=1, prev1=2?
- 这是初始化状态,对应楼梯数为1和2时的解
- 当计算第3阶时:需要前两阶的解(1阶和2阶)
- prev2代表dp[i-2](1阶的解=1)
- prev1代表dp[i-1](2阶的解=2)
状态更新过程(以n=5为例):
1 | i=3: current = 2 + 1 = 3, prev2=2, prev1=3 |
时间复杂度:O(n)
空间复杂度:O(1) - 只使用常数个变量
3. 动态规划算法核心思想详解
3.1 动态规划的本质
动态规划是一种将复杂问题分解为简单子问题的算法思想,通过存储中间结果来避免重复计算。
3.2 动态规划的适用条件
- 最优子结构:问题的最优解包含其子问题的最优解
- 重叠子问题:递归算法会反复求解相同的子问题
3.3 动态规划的解题步骤
- 定义状态:dp[i]表示什么含义
- 确定状态转移方程:dp[i]与dp[i-1], dp[i-2]等的关系
- 初始化边界条件:最小子问题的解
- 确定计算顺序:自底向上或自顶向下
- 空间优化(可选):减少存储空间
3.4 爬楼梯问题的状态定义
- 状态:dp[i]表示爬i阶楼梯的方法数
- 转移方程:dp[i] = dp[i-1] + dp[i-2]
- 边界条件:dp[1] = 1, dp[2] = 2
- 计算顺序:从3到n依次计算
4. 性能对比分析
4.1 时间复杂度对比
| 算法 | 时间复杂度 | 适用场景 |
|---|---|---|
| 暴力递归 | O(2^n) | 教学演示,实际不可用 |
| 记忆化搜索 | O(n) | 递归思维,中等规模 |
| 标准动态规划 | O(n) | 通用解法,易于理解 |
| 优化动态规划 | O(n) | 生产环境,空间最优 |
4.2 空间复杂度对比
| 算法 | 空间复杂度 | 说明 |
|---|---|---|
| 暴力递归 | O(n) | 递归栈空间 |
| 记忆化搜索 | O(n) | 记忆数组+递归栈 |
| 标准动态规划 | O(n) | DP数组 |
| 优化动态规划 | O(1) | 常数个变量 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 John Ding!