做动态规划问题时,肯定会对dp
数组的遍历顺序有些头疼,拿二维dp
数组来举例
有时候是正向遍历:
1 | int[][] dp = new int[m][n]; |
有时候反向遍历:
1 | for (int i = m - 1; i >= 0; i--) |
有时候可能会斜向遍历:
1 | // 斜着遍历数组 |
甚至更让人迷惑的是,有时候发现正向反向遍历都可以得到正确答案。
仔细观察的话,只要把住两点就行了:
1、遍历的过程中,所需的状态必须是已经计算出来的。
2、遍历的终点必须是存储结果的那个位置。
比如编辑距离这个经典的问题,我们通过对dp
数组的定义,确定了 base case 是dp[..][0]
和dp[0][..]
,最终答案是dp[m][n]
;而且我们通过状态转移方程知道dp[i][j]
需要从dp[i-1][j]
,dp[i][j-1]
,dp[i-1][j-1]
转移而来,如下图:
那么,参考刚才说的两条原则,该怎么遍历dp
数组?肯定是正向遍历:
1 | for (int i = 1; i < m; i++) |
因为,这样每一步迭代的左边、上边、左上边的位置都是 base case 或者之前计算过的,而且最终结束在我们想要的答案dp[m][n]
。