542. 01 矩阵、1162. 地图分析、994. 腐烂的橘子

2021-11-07  本文已影响0人  Abeants

本次的三道题都用了多源点BFS的方法,关于什么是多源点BFS呢,就是求很多个起点到一个终点的关系,就将终点入队,反过来求。如下面三道题:

542. 01 矩阵

给定一个由 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]]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/01-matrix
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路及方法

这道题要求的是每一个1离最近0的距离,那么可以假设这个矩阵就只有一个0,其余的都是1,就是多源点BFS问题,所以就将所有的0入队,然后开始用BFS来计算。

用一个新的dist矩阵来记录每一个1距离最近的0的距离。

class Solution {
    // 方向
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    public int[][] updateMatrix(int[][] mat) {
        int m = mat.length,n = mat[0].length;
        // 记录已访问的节点
        boolean[][] visited = new boolean[m][n];
        // 初始队列
        Queue<int[]> queue = new LinkedList<>();
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat[0].length; j++) {
                // 所有0全部入队
                if (mat[i][j] == 0) {
                    queue.offer(new int[]{i, j});
                    visited[i][j] = true;
                }
            }
        }

        // 记录距离
        int[][] dist = new int[m][n];
        // 搜索0位置的四周,并记录距离
        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int row = cur[0], cln = cur[1];
            for (int i = 0; i < 4; i++) {
                int ni = row + dirs[i][0];
                int nj = cln + dirs[i][1];
                if (ni >= 0 && nj >= 0 && ni < m &&  nj < n && !visited[ni][nj]) {
                    dist[ni][nj] = dist[row][cln] + 1;
                    queue.offer(new int[]{ni, nj});
                    visited[ni][nj] = true;
                }
            }
        }

        return dist;
    }
}

结果如下:

1162. 地图分析

你现在手里有一份大小为 N x N 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的。

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

如果网格上只有陆地或者海洋,请返回 -1。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/as-far-from-land-as-possible
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路及方法

这道题跟上面是同样的方法,只不过是找到0距离最近的1的距离,所以就将所有的1入队,然后进行BFS算法。

注意需要判断全1或者全0的情况,就只用判断队列的长度是否为m*n或者0。

class Solution {
    // 方向
    static int[][] dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    public int maxDistance(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        // 初始队列
        Queue<int[]> queue = new LinkedList<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    queue.offer(new int[]{i, j});
                } else {
                    grid[i][j] = -1;
                }
            }
        }
        // 如果全为陆地或嗨哟
        if (queue.size() == m * n || queue.size() == 0) return -1;
        // BFS
        while (!queue.isEmpty()) {
            int[] cur = queue.poll();
            int row = cur[0], cln = cur[1];
            for (int i = 0; i < 4; i++) {
                int newRow = row + dirs[i][0];
                int newCln = cln + dirs[i][1];
                if (newRow < 0 || newCln < 0 || newRow >= m || newCln >= n || grid[newRow][newCln] > 0) continue;
                grid[newRow][newCln] = grid[row][cln] + 1;
                // 周围节点入队
                queue.offer(new int[]{newRow, newCln});
            }
        }

        int maxDist = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                maxDist = Math.max(maxDist, grid[i][j]);
            }
        }

        return maxDist - 1;
    }
}

结果如下:

994. 腐烂的橘子

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

值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,任何与腐烂的橘子(在 4 个正方向上)相邻的新鲜橘子都会腐烂。

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotting-oranges
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路及方法

一样的思想,腐烂的橘子先入队,然后影响周围的橘子。

需要判断的是没有橘子,即全0的情况,就用一个参数计数。

class Solution {
    public static int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

    public int orangesRotting(int[][] grid) {
        int m = grid.length, n = grid[0].length;

        int countZero = 0;
        // 初始队列
        Queue<int[]> queue = new LinkedList<>();
        // 所有腐烂橘子入队
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 2) {
                    queue.offer(new int[]{i, j});
                }
                // 考虑0的情况
                if (grid[i][j] == 0) {
                    countZero++;
                }
            }
        }
        // 如果没有橘子
        if (countZero == m * n) return 0;

        int time = 0;
        // BFS将所有腐烂橘子四周的橘子腐烂
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                int[] cur = queue.poll();
                int row = cur[0], cln = cur[1];
                // 四周橘子腐烂
                for (int j = 0; j < 4; j++) {
                    int newRow = row + dirs[j][0];
                    int newCln = cln + dirs[j][1];
                    // 出界或者周围不是新鲜橘子,continue
                    if (newRow < 0 || newCln < 0 || newRow >= m || newCln >= n || grid[newRow][newCln] != 1) continue;
                    grid[newRow][newCln] = 2;
                    queue.offer(new int[]{newRow, newCln});
                }
            }
            // 更新时间
            time++;
        }

        // 判断是否还有新鲜橘子
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) return -1;
            }
        }
        
        return time - 1;
    }
}

结果如下:

上一篇下一篇

猜你喜欢

热点阅读