动态规划的核心,无非是定义状态、找到转移,再按顺序填表。很多问题都能套进一个类似斐波那契的递推结构中,比如泰波那契、爬楼梯、解码方法——它们都在dp[i]依赖于前几项的值,只是依赖的规则略有不同。
下面用四道 LeetCode 题目,看一下这个模型的几处变形。
第 N 个泰波那契数(LeetCode 1137)
题目要求:T0 = 0, T1 = 1, T2 = 1,且 Tn = Tn-1 + Tn-2 + Tn-3(n >= 3)。返回 Tn。

状态表示很直接:dp[i] 即第 i 个泰波那契数。转移方程即为dp[i] = dp[i-1] + dp[i-2] + dp[i-3]。初始化前三个值,然后从左往右填即可。
// 时间复杂度:O(N)
// 空间复杂度:O(N)
class Solution {
public int tribonacci(int n) {
if (n < 3) return n == 0 ? 0 : 1;
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = dp[2] = 1;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3];
}
return dp[n];
}
}
这里可以很容易优化空间,因为每次只用最近三个数。滚动数组的做法:
// 时间复杂度:O(N)
// 空间复杂度:O(1)
{
{
(n < ) n == ? : ;
[] dp = []{, , };
( ; i <= n; i++) {
dp[];
dp[] = dp[];
dp[] = dp[];
dp[] = tmp + dp[] + dp[];
}
dp[];
}
}




