Java_多源_BFS_地图分析(❗❗❗经典面试题❗❗❗)

337 阅读4分钟

题目链接:leetcode.cn/problems/as…

题目描述:

你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 01 标记好了。其中 0 代表海洋,1 代表陆地。

请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1

我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0)(x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1|

示例 1:

img

 输入:grid = [[1,0,1],[0,0,0],[1,0,1]]
 输出:2
 解释: 
 海洋单元格 (1, 1) 和所有陆地单元格之间的距离都达到最大,最大距离为 2

示例 2:

img

 输入:grid = [[1,0,0],[0,0,0],[0,0,0]]
 输出:4
 解释: 
 海洋单元格 (2, 2) 和所有陆地单元格之间的距离都达到最大,最大距离为 4

提示:

  • n == grid.length
  • n == grid[i].length
  • 1 <= n <= 100
  • grid[i][j] 不是 0 就是 1

解析

将BFS全部搞懂,直接看我前面的几个题目分别是图像渲染——迷宫中离入口最近的出口——多源BFS矩阵

这题题目阅读理解难度大于题目本身。找到一个海洋区域,这个海洋区域到与它最近的陆地区域的距离是最大的。

再简单一点讲,先假设有一个陆地,多个海洋,找出海洋离陆地最远的那个。只不过现在有多个陆地,也就是单源变成多源了。

题目中的曼哈顿距离其实就是横坐标的差加上纵坐标的差

这题其实和矩阵只有一点点区别,矩阵要返回的是所有的值,这题返回的是最大值而已。

和矩阵一样,这题我们的思路还是从陆地去找海洋,因为陆地旁边的海洋是第一层,而直接从海洋开始找的话你不知道你处于第几层。

那么从陆地出发的话我们就要先将所有的陆地存起来,那这里就需要重新创建一个规模一样的表。表中的值初始化为-1(与题目中的值无关,方便判断),然后原来的陆地(为1的值)赋值为0,为什么初始化为0,因为后面赋值要用到。

然后拿着这些陆地去遍历,将它周围的第一层的海洋找出来,并赋值为这一层的值加一,这就是赋值为0的原因,如果你还是初始化为1的话,再加一就变成2了。为什么是直接赋值为这一层的值加一呢?不应该是|x0 - x1| + |y0 - y1|吗,我们已经初始化陆地为0了,我们从陆地往外扩第一层的值应该就是陆地的上下左右位置,这个上下左右位置距离中间的距离都是1,所以直接上一层的值也就是0再加1就行,第二层的话就是1 + 1。以此类推。

最后再在循环外定义一个最大值就行。

代码

 class Solution {
     static int[] dx = {0, 0, 1, -1};
     static int[] dy = {1, -1, 0, 0};
     public int maxDistance(int[][] grid) {
         Queue<int[]> queue = new LinkedList<>();
         //因为此处是n * n,所以定义一个就行
         int n = grid.length;
         //定义一个规格相同的数组方便值
         int[][] arr = new int[n][n];
         for (int i = 0; i < n; i++) {
             for (int j = 0; j < n; j++) {
                 //先将数组初始化为-1
                 arr[i][j] = -1;
                 if (grid[i][j] == 1) {
                     //将值为1的位置赋值为0
                     arr[i][j] = 0;
                     //再将值为1的存到队列中
                     queue.add(new int[]{i,j});
                 } 
             }
         }
         //判断是否都为海洋或者陆地
         if (queue.size() == n * n || queue.isEmpty()) {
             return -1;
         }
         //定义result用于存储最大值
         int result = 1;
         while (!queue.isEmpty()) {
             int[] cur = queue.poll();
             int x = cur[0], y = cur[1];
             //往外扩
             for (int i = 0; i < 4; i++) {
                 int x1 = x + dx[i], y1 = y + dy[i];
                 if (x1 < n && x1 >= 0 && y1 < n && y1 >= 0 && arr[x1][y1] == -1) {
                     //这一层现在还处于x,y也就是我们正在遍历的这一层。下一层其实就是x1,y1
                     //所以赋值直接就是arr[x1][y1] = arr[x][y] + 1;
                     arr[x1][y1] = arr[x][y] + 1;
                     //再将下一层存入到queue中
                     queue.add(new int[]{x1,y1});
                     //更新最大值
                     result = Math.max(result,arr[x1][y1]);
                 }
             }
         }
         return result;
     }
 }