leetcode
leetcode 251 ~ 300
墙与门

墙与门

难度:

标签:

题目描述

代码结果

运行时间: 67 ms, 内存: 19.5 MB


/*
 * 题目:墙与门
 * 你被给定一个 m × n 的二维网格,网格中有以下几种可能的初始化值:
 * -1 表示墙或是障碍物
 * 0 表示一扇门
 * INF 无限表示一个空的房间
 * 你需要填充每个空房间到最近门的距离,如果无法到达门,则填充 INF
 *
 * 思路:
 * 使用广度优先搜索(BFS)从每个门(值为0)开始,将距离依次填充到周围的空房间
 */
 
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.stream.IntStream;
 
public class WallsAndGatesStream {
    private static final int INF = Integer.MAX_VALUE;
 
    public void wallsAndGates(int[][] rooms) {
        if (rooms == null || rooms.length == 0) return;
 
        int m = rooms.length;
        int n = rooms[0].length;
        Queue<int[]> queue = new LinkedList<>();
 
        // 将所有的门加入队列
        IntStream.range(0, m).forEach(i ->
            IntStream.range(0, n).filter(j -> rooms[i][j] == 0).forEach(j -> queue.offer(new int[]{i, j}))
        );
 
        // 四个方向
        int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
 
        // BFS 处理
        while (!queue.isEmpty()) {
            int[] point = queue.poll();
            int row = point[0];
            int col = point[1];
 
            Arrays.stream(directions).forEach(direction -> {
                int newRow = row + direction[0];
                int newCol = col + direction[1];
 
                // 检查边界和是否是空房间
                if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && rooms[newRow][newCol] == INF) {
                    // 更新距离并将新的房间加入队列
                    rooms[newRow][newCol] = rooms[row][col] + 1;
                    queue.offer(new int[]{newRow, newCol});
                }
            });
        }
    }
}

解释

方法:

这个题解使用广度优先搜索(BFS)的方法来解决问题。首先,遍历整个rooms矩阵,找到所有的门(值为0的格子),并将它们的坐标添加到一个队列search_queue中。然后,不断从队列中取出格子,对于每个格子,检查其四个相邻的格子。如果相邻格子是空的(值为inf),就将其距离设置为当前格子的距离+1,并将相邻格子加入队列。这样不断扩展,直到队列为空,所有可达的空格子都被填入正确的距离值。

时间复杂度:

O(m*n)

空间复杂度:

O(m*n)

代码细节讲解

🦆
为什么在BFS解法中,一开始只将门的位置加入搜索队列,而不是所有的格子?
在BFS解法中,一开始只将门的位置加入搜索队列是因为门是距离计算的起点,门的位置本身的距离值为0,代表最短距离的起始点。从门开始,逐步向外扩展到相邻的格子,能够保证每一个空格子被计算的距离都是从最近的门开始计算的最短距离。如果一开始将所有格子都加入队列,将无法保证逐层扩展的过程中能够正确计算出每个空格子至最近门的最短距离,且会增加不必要的计算复杂度和资源消耗。
🦆
在BFS扩展过程中,更新相邻格子的距离时,有没有可能出现重复更新同一个格子的情况?如果有,这会对算法的效率产生什么影响?
在BFS扩展过程中,由于每个格子在被发现并加入队列时其距离就已经被设定为从起点到该点的最短距离,因此不会出现重复更新同一个格子的情况。一旦格子的距离被设置并加入队列,其距离就是确定的,后续不会有来自其他路径的更新覆盖这个距离。这种方法确保了每个格子的距离值只被计算一次,从而提高算法的效率,避免不必要的重复计算。
🦆
当矩阵中不包含任何门时,题解的BFS方法会如何处理?是否有必要对这种情况进行特殊处理来提升效率?
当矩阵中不包含任何门时,由于搜索队列初始为空,BFS过程实际上不会执行任何操作。这种情况下,所有格子的值(如果原始值为inf)将保持不变,因为没有门可以作为起点来更新距离。在这种特殊情况下,算法已经足够有效,因为它不会进行任何无效的操作或计算。因此,没有必要对这种情况进行特殊处理,因为算法本身在没有门时不会执行距离更新,这已经是效率最优的处理方式。

相关问题

被围绕的区域

给你一个 m x n 的矩阵 board ,由若干字符 'X''O' ,找到所有被 'X' 围绕的区域,并将这些区域里所有的 'O''X' 填充。

 

示例 1:

输入:board = [["X","X","X","X"],["X","O","O","X"],["X","X","O","X"],["X","O","X","X"]]
输出:[["X","X","X","X"],["X","X","X","X"],["X","X","X","X"],["X","O","X","X"]]
解释:被围绕的区间不会存在于边界上,换句话说,任何边界上的 'O' 都不会被填充为 'X'。 任何不在边界上,或不与边界上的 'O' 相连的 'O' 最终都会被填充为 'X'。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

示例 2:

输入:board = [["X"]]
输出:[["X"]]

 

提示:

  • m == board.length
  • n == board[i].length
  • 1 <= m, n <= 200
  • board[i][j]'X''O'

岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

 

示例 1:

输入:grid = [
  ["1","1","1","1","0"],
  ["1","1","0","1","0"],
  ["1","1","0","0","0"],
  ["0","0","0","0","0"]
]
输出:1

示例 2:

输入:grid = [
  ["1","1","0","0","0"],
  ["1","1","0","0","0"],
  ["0","0","1","0","0"],
  ["0","0","0","1","1"]
]
输出:3

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0''1'

离建筑物最近的距离

离建筑物最近的距离

扫地机器人

扫地机器人

腐烂的橘子

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

  • 值 0 代表空单元格;
  • 值 1 代表新鲜橘子;
  • 值 2 代表腐烂的橘子。

每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

 

示例 1:

输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4

示例 2:

输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个方向上。

示例 3:

输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 10
  • grid[i][j] 仅为 01 或 2