Nameless Site

But one day, you will stand before its decrepit gate,without really knowing why.

0%

01矩阵

来自Leetcode第542题01矩阵

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

示例 2:
输入:

1
2
3
0 0 0
0 1 0
1 1 1

输出:

1
2
3
0 0 0
0 1 0
1 2 1

BFS

首先把每个源点 0 入队,然后从各个 0 同时开始一圈一圈的向 1 扩散(每个 1 都是被离它最近的 0 扩散到的 ),扩散的时候可以设置 boolean[][] visited 标志是否访问过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public int[][] updateMatrix(int[][] matrix) {
int row = matrix.length,col = matrix[0].length;
Queue<int[]> queue = new LinkedList<>();
boolean[][] seen = new boolean[row][col];
int[][] d = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for(int i = 0 ; i < row ; ++i){
for(int j = 0 ; j < col ; ++j){
if(matrix[i][j] == 0){
seen[i][j] = true;
queue.add(new int[]{i,j});
}
}
}
int[] tmp;
int dx,dy;
while (!queue.isEmpty()){
tmp = queue.poll();
for(int k = 0 ; k < 4 ; ++k){
dx = tmp[0]+d[k][0];
dy = tmp[1]+d[k][1];
if(dx >= 0 && dx < row && dy >= 0 && dy < col && !seen[dx][dy]){
matrix[dx][dy] = matrix[tmp[0]][tmp[1]] + 1;
queue.offer(new int[]{dx,dy});
seen[dx][dy] = true;
}
}
}
return matrix;
}

动态规划

用dp[i][j]表示该位置距离最近的0的距离,则dp[i][j] = 1+min(dp[i-1][j],dp[i][j-1],dp[i+1][j],dp[i][j+1]) if matrix[i][j] == 1

尝试将问题分解:

  1. 距离 (i, j) 最近的 0 的位置,是在其 「左上,右上,左下,右下」4个方向之一;
  2. 因此我们分别从四个角开始递推,就分别得到了位于「左上方、右上方、左下方、右下方」距离 (i, j)的最近的 0 的距离,取 min即可;
  3. 通过上两步思路,我们可以很容易的写出 4 个双重 for循环,动态规划的解法写到这一步其实已经完全 OK 了;
  4. 如果第三步还不满足的话,从四个角开始的4次递推,其实还可以优化成从任一组对角开始的2次递推,比如只写从左上角、右下角开始递推就行了。

对dp数组初始化时不能将其设置为0X7FFFFFFF,不然+1就会溢出,变成-2147483647.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public int[][] updateMatrix(int[][] matrix) {
int row = matrix.length,col = matrix[0].length;
int[][] dp = new int[row][col];
for(int i = 0 ; i < row ; ++i)
for(int j = 0 ; j < col ; ++j)
dp[i][j] = matrix[i][j] == 0 ? 0 : 10000;

//从左上角开始
for(int i = 0 ; i < row ; ++i){
for (int j = 0 ; j < col ; ++j){
if(i > 0)
dp[i][j] = Math.min(dp[i][j],dp[i-1][j]+1);
if(j > 0)
dp[i][j] = Math.min(dp[i][j],dp[i][j-1]+1);
}
}

//从右下角开始
for(int i = row - 1 ; i >= 0 ; --i){
for(int j = col - 1 ; j >= 0 ; --j){
if(i < row - 1)
dp[i][j] = Math.min(dp[i][j],dp[i+1][j]+1);
if(j < col - 1)
dp[i][j] = Math.min(dp[i][j],dp[i][j+1]+1);
}
}
return dp;
}