讲述
-
区间动态规划,顾名思义,就是在区间上进行动态规划。
-
通常情况下,这类问题在进行一次决策后,决策区间会由一个大区间分成两个小区间,问题也由一个规模较大问题分解成两个规模较小的问题。
这里的一次决策,相当于将一个大的集合划分成两个小的集合。
-
这样,就可以从长度较小的区间向长度较长的区间进行递推。
例题1:矩阵最优连乘
解答:
个人感觉和【石子合并】是相同的。属于那种比较直观的典型的区间DP问题。
例题2:括号匹配(子序列)⭐⭐⭐⭐⭐
需要注意上面的第四点,st匹配,我之前忽略了这种情况。
“否则”要去掉。
这里的解题思路是根据括号匹配的三种情况而来的。
- 第一种是空串括号匹配。这个无需多言;
- 第二种是
s
括号匹配,则(s)
与[s]
括号匹配。这种情况发生的条件是子序列的左右分别出现[
和]
或者(
和)
;- 第三种是
s
,t
括号匹配,则st
括号匹配。这种情况就要枚举所有的可能的相邻匹配了。其实就是相当于模式匹配,枚举这三种模式匹配的情况!
例题3:石子合并
不相邻就用哈夫曼树解题~
还是和矩阵最优连乘一样,你要合并肯定包括最后两堆和合并。那么就可以 枚举分割点 了!
例题4:环形石子合并
这里就变成了
O
(
(
2
n
)
3
)
O((2n)^3)
O((2n)3) ,只是常数变大了一些而已。妙啊,远远由于
O
(
n
4
)
O(n^4)
O(n4)。
模板总结
区间DP模板是三重循环:
- 一重循环:区间长度
- 二重循环:区间起点
- 三重循环:区间分割点
区间 DP 常用模版 所有的区间dp问题,第一维都是枚举区间长度,一般 len = 1
用来初始化,枚举从 len = 2
开始,第二维枚举起点 i
(右端点 j
自动获得,j = i + len - 1
)
// 先初始化区间长度为1的情况
for (int i = 1; i <= n; i++) {
dp[i][i] = 初始值
}
//区间长度
for (int len = 2; len <= n; len++)
//枚举起点
for (int i = 1; i + len - 1 <= n; i++) {
//区间终点
int j = i + len - 1;
for (int k = i; k < j; k++) {
//枚举分割点,构造状态转移方程
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + w[i][j]);
}
}
题型训练
- ⭐⭐⭐⭐⭐【区间DP】LeetCode 664. Strange Printer
- ⭐⭐⭐⭐⭐【区间DP】LeetCode 312. Burst Balloons
- 最长回文子序列
- ⭐⭐⭐⭐⭐【区间DP】LeetCode 1039. Minimum Score Triangulation of Polygon