题目链接:leetcode.cn/problems/2b…
题目描述:
给定一个由 0
和 1
组成的矩阵 mat
,请输出一个大小相同的矩阵,其中每一个格子是 mat
中对应位置元素到最近的 0
的距离。
两个相邻元素间的距离为 1
。
示例 1:
输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
示例 2:
输入: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
解析
迷宫中离入口最近的出口是单源最短路径问题,也就是只有一个入口,这题是多源最短路径问题。
如果你把着图像渲染、迷宫中离入口最近的出口和这题全部理解透彻,那么BFS的绝大多数题你都可以解了,毕竟每题之间都有联系,而且变化是不大的。
那我们来看这题,题目中开始会给这个矩阵中放若干个0
,0
的个数大于零,然后其余都是1,让我们将这些为1的格子中的数重置为 它们到达 离最近的0的路径长度.
这题还有很多细节需要处理,如果我们从1的点往外面扩然后寻找0的话会很麻烦,你需要处理层数,因为有多条路径,还需要判断那条路径为最短。所以我们如果从0出发的话就很简单,从0往外扩,第一层的话我们赋值为1,然后将第一层的节点个数添加到队列中,再往第二层扩,第二次扩的时候需要赋值为二,所以我们开始先创建一个一模一样的二维数组,然后全部赋值为-1,再遍历原数组,将为0的值的位置获取到,覆盖到我们新创建的二维数组中。
那这里的赋值我们可以怎么处理呢?通过规律发现,下一层步数的值都是这层的步数加一,所以待会再赋值的时候就不需要单独像迷宫那题一样创建step来单独记录当前的步数了。
迷宫的那题我们需要这一层的所有节点个数,也就是queue.size()
,然后再遍历,这题我们也不需要,这里步数的规律已经获取到了,下一层步数的值都是这层的步数加一,而且步数是直接赋值到数组中去的。单这样讲有点抽象,我们直接看代码吧。
代码
class Solution {
static int[] dx = {0,0,1,-1};
static int[] dy = {1,-1,0,0};
public int[][] updateMatrix(int[][] mat) {
//先获取到数组的长度
int m = mat.length;
int n = mat[0].length;
//在创建一个一模一样的数组用来存修改后的数组
int[][] result = new int[m][n];
//将这个数组中的值初始化为-1
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
result[i][j] = -1;
}
}
//创建queue
Queue<int[]> queue = new LinkedList<>();
//将0的位置覆盖到result中
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (mat[i][j] == 0) {
result[i][j] = 0;
//将初始层“第0层”放到queue中
queue.add(new int[]{i,j});
}
}
}
while (!queue.isEmpty()) {
//获取坐标
int[] cur = queue.poll();
int x = cur[0];
int y = cur[1];
//开始像外扩
for (int i = 0; i < 4; i++) {
int x1 = x + dx[i];
int y1 = y + dy[i];
//判断此坐标是否满足基本条件且是否走过
if (x1 >= 0 && x1 < m && y1 >= 0 && y1 < n && result[x1][y1] == -1) {
//将这个坐标的步数赋值为这一层加一
result[x1][y1] = result[x][y] + 1;
//添加到queue中,继续遍历
queue.add(new int[]{x1,y1});
}
}
}
return result;
}
}