Java实现多源_BFS_矩阵(❗❗❗经典面试题❗❗❗)

190 阅读3分钟

题目链接:leetcode.cn/problems/2b…

题目描述:

给定一个由 01 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。

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

示例 1:

img

 输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
 输出:[[0,0,0],[0,1,0],[0,0,0]]

示例 2:

img

 输入: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的绝大多数题你都可以解了,毕竟每题之间都有联系,而且变化是不大的。

那我们来看这题,题目中开始会给这个矩阵中放若干个00的个数大于零,然后其余都是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;
     }
 }