leetcode
leetcode 251 ~ 300
离建筑物最近的距离

离建筑物最近的距离

难度:

标签:

题目描述

代码结果

运行时间: 1352 ms, 内存: 16.3 MB


/*
 * Leetcode Problem 317: Shortest Distance from All Buildings
 * 
 * Approach using Java Streams (where applicable):
 * 1. Initialize distance and reach arrays to store the sum of distances and the number of buildings reached from each cell.
 * 2. Use BFS from each building to compute distances to all reachable empty lands.
 * 3. Use Streams to find the minimum distance cell which can reach all buildings.
 */
 
import java.util.*;
import java.util.stream.IntStream;
 
public class SolutionStream {
    public int shortestDistance(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] distance = new int[m][n];
        int[][] reach = new int[m][n];
        int numBuildings = 0;
        int[] dx = {-1, 1, 0, 0};
        int[] dy = {0, 0, -1, 1};
 
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    numBuildings++;
                    boolean[][] visited = new boolean[m][n];
                    Queue<int[]> queue = new LinkedList<>();
                    queue.offer(new int[]{i, j});
                    int level = 1;
                    while (!queue.isEmpty()) {
                        int size = queue.size();
                        for (int k = 0; k < size; k++) {
                            int[] cur = queue.poll();
                            for (int d = 0; d < 4; d++) {
                                int x = cur[0] + dx[d];
                                int y = cur[1] + dy[d];
                                if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 0 && !visited[x][y]) {
                                    visited[x][y] = true;
                                    distance[x][y] += level;
                                    reach[x][y]++;
                                    queue.offer(new int[]{x, y});
                                }
                            }
                        }
                        level++;
                    }
                }
            }
        }
 
        return IntStream.range(0, m).boxed()
            .flatMap(i -> IntStream.range(0, n).filter(j -> grid[i][j] == 0 && reach[i][j] == numBuildings).mapToObj(j -> distance[i][j]))
            .min(Integer::compare)
            .orElse(-1);
    }
}

解释

方法:

该题解采用BFS(广度优先搜索)的方法。首先遍历网格,找到所有建筑物的位置,然后以每个建筑物为起点进行BFS。在BFS过程中,记录每个空地到当前建筑物的距离,并将距离累加到dist数组中。同时,将访问过的空地标记为负数,避免重复访问。最后,遍历dist数组,找到到所有建筑物距离之和最小的空地,返回其距离和。如果没有符合条件的空地,则返回-1。

时间复杂度:

O(b*m*n),其中b为建筑物的数量

空间复杂度:

O(m*n)

代码细节讲解

🦆
为什么在BFS过程中,需要将访问过的空地标记为负数,这种标记方式与其他可能的标记方式相比有什么优势?
在BFS过程中,将访问过的空地标记为负数是为了防止同一层或不同层的BFS重复访问同一个空地,从而导致不必要的计算和错误的距离累加。这种标记方式利用了原始网格数组,减少了额外空间的需求,也使得状态的更新(即标记为空地已访问)与检查(是否已访问过)更为直接和高效。相比于使用额外的visited数组来记录访问状态,这种方法节省了空间并简化了代码逻辑。
🦆
在进行BFS时,每增加一层,距离变量`dis`是如何确保正确地反映从起点到当前节点的实际距离的?
在BFS过程中,`dis`变量在每完成一层的遍历后增加1。由于BFS按层遍历,每一层的所有节点都与起点的距离相同,并且比上一层每个节点的距离多1。因此,通过这种逐层增加的方式,`dis`能够准确地反映从起点到当前节点的实际距离。这保证了无论何时将一个新节点加入队列,其记录的距离都是正确的。
🦆
你是如何处理多个建筑物可能会重复访问同一个空地的情况,以确保每个空地到不同建筑物的距离只被计算一次?
在算法中,每遍历到一个建筑物,会将当前建筑物的标记值(开始为1)递减(变为0,然后-1,依此类推)。当BFS从一个建筑物开始时,只有那些标记值等于当前建筑物标记的空地才能被访问和更新。因此,每个空地只会与当前正在进行BFS的建筑物关联一次,确保每个空地到不同建筑物的距离只被计算一次。这通过动态地调整grid中的值来防止重复访问和重复计算。
🦆
在找到所有建筑物的位置后,你是如何决定从哪个建筑物开始BFS的?是否考虑了从特定的建筑物开始可能会影响最终的最短距离计算?
在这个算法中,从哪个建筑物开始BFS并不影响最终结果,因为算法的目标是计算每个空地到所有建筑物的距离总和。算法确保了每个空地都会被每个建筑物访问一次,无论BFS的起始顺序如何。因此,不需要特别考虑从某个特定建筑物开始的问题。所有建筑物最终都会均等地对结果产生影响,确保了计算的公正性和正确性。

相关问题

墙与门

墙与门

最佳的碰头地点

最佳的碰头地点

地图分析

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

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

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

 

示例 1:

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

示例 2:

输入: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