动态规划基础
动态规划本质上是某种状态的公式加上一个提前计算好值的容器。通过求出当前位置的值并放入容器中供后续使用,从而解决复杂问题。初始值通常是可见的,由此启动整个计算过程。
严格来说:动态规划 = 状态定义 + 状态转移方程 + 初始条件 + 状态存储
动规五步法
- 状态表示:即 dp 表中 dp[i] 的含义,通常结合题目要求分析子问题。
- 状态转移方程:推导 dp[i] 的具体计算公式,这是最难的一步。
- 初始化:保证填表时不越界,根据题目设定初始值。
- 填表顺序:确保计算当前状态时所需的前置状态已计算完成,通常从左向右或从上到下。
- 返回值:根据题意从 dp 表中提取最终结果。
提示:状态表示通常为'以 i 位置结尾/开头',dp[i] 通常通过最后一个状态进行分析;初始化通常通过第一个状态进行分析。处理数字字符判断时,建议转换为数字而非直接比较字符,避免边界错误。
实战演练
1. 第 N 个泰波那契数
这道题是典型的线性递推。我们需要求第 n 个泰波那契数,其规律类似于斐波那契数列,但依赖前三个数。
核心逻辑:
- 状态表示:dp[i] 表示第 i 个泰波那契数。
- 转移方程:dp[i] = dp[i-1] + dp[i-2] + dp[i-3]。
- 空间优化:由于只依赖前三个数,可以使用滚动变量代替数组。
class Solution {
public:
int tribonacci(int n) {
// 空间优化写法:使用三个变量维护前三个状态
if (n == 0) return 0;
if (n == 1 || n == 2) return 1;
int a = 0, b = 1, c = 1;
int ret = 0;
for (int i = 3; i <= n; ++i) {
ret = a + b + c;
a = b;
b = c;
c = ret;
}
return ret;
}
};


