题目:
给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,
其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
![在这里插入图片描述](https://img-blog.csdnimg.cn/f6bd042587074301897a8c61a8cfb1c7.png)
输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
![在这里插入图片描述](https://img-blog.csdnimg.cn/c759c35b4b8445e7aa6f2717d5db3bf1.png)
输入:mat = [[0,0,0],[0,1,0],[1,1,1]]
输出:[[0,0,0],[0,1,0],[1,2,1]]
提示:
m == mat.length
n == mat[i].length
1 <= m, n <= 104
1 <= m * n <= 104
mat[i][j] is either 0 or 1.
mat 中至少有一个 0
------------------------
思路:
如果想要理解两次DP的正确性,请先确保自己已经懂得了四方向DP的解法。
首先我们定义dp[i][j] 为mat[i][j] 到 0 的最短距离,显然我们有以下状态转移方程:
dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i+1][j], dp[i][j+1]) + 1, mat[i][j] = 1
dp[i][j] = 0, mat[i][j] = 0
然后需要说明的是,双向DP指的是从左上到右下和从右下到左上分别运行一次动态规划算法,
运行后便得到了答案(另一条对角线也可以)。
再则需要说明的是,双向DP的理解难点在哪里?前面我们提到从左上到右下动态规划,
那么此时dp[i][j]表示的是mat[i][j]到其左上部分0的最短距离;
从右下到左上动态规划,dp[i][j]表示的是mat[i][j]到其右下部分0的最短距离,
那么从字面上看有一个很直接的疑惑,
mat[i][j]到其右上部分或者左下部分0的距离有没有被考虑到呢?
下面我们来回答这个问题,先给出答案:都考虑到了。那么为什么呢?假设我们现在从左上到右下已经遍历完,正在执行从右下到左上的遍历,此刻到了dp[i][j]
对于右上部分,如果该部分有0,那么到其最近的距离已经在第一次遍历时被dp[i][k],
j < k < cols给考虑到了,而我们第二次遍历时,dp[i][j] 可能是根据它右边的值来的,
所以右上部分的0没有被遗漏;
对于左下部分,如果该部分有0,那么到其最近的距离已经在第二次遍历时被dp[p][q],
i < p < rows, 0 <= q < cols or p = i, j < q < cols给考虑到了,
而dp[i][j] 可能是根据它下边的值来的,所以左下部分的0也没有被遗漏。
综上,只需要两次DP即可得出答案。
--------------------------
class Solution {
public int[][] updateMatrix(int[][] mat) {
int row = mat.length;
int col = mat[0].length;
int[][] dp = new int[row + 2][col + 2];
for (int i = 0; i < dp.length; i++) {
dp[i][0] = dp[i][col + 1] = Integer.MAX_VALUE >> 1;
}
for (int j = 0; j < dp[0].length; j++) {
dp[0][j] = dp[row + 1][j] = Integer.MAX_VALUE >> 1;
}
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= col; j++) {
if (mat[i - 1][j - 1] == 0) dp[i][j] = 0;
else dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1;
}
}
for (int i = row; i >= 1; i--) {
for (int j = col; j >= 1; j--) {
if (mat[i - 1][j - 1] == 1) {
dp[i][j] = Math.min(dp[i][j], Math.min(dp[i + 1][j], dp[i][j + 1]) + 1);
}
}
}
int[][] res = new int[row][col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
res[i][j] = dp[i + 1][j + 1];
}
}
return res;
}
}
LC