01 矩阵

195 阅读2分钟

题目

image.png

多源BFS

public int[][] updateMatrix(int[][] matrix) {

        // distance[i][j] 代表每个位置到0的最短距离
        int [][] distance = new int[matrix.length][matrix[0].length];
        boolean [][] visited = new boolean[matrix.length][matrix[0].length];
        Queue<int []> queue = new LinkedList();


        for (int i = 0; i < matrix.length; i ++) {
            for (int j = 0; j < matrix[0].length; j ++) {
                if (matrix[i][j] == 0) {
                    queue.offer(new int[]{i, j});
                    distance[i][j] = 0;
                    visited[i][j] = Boolean.TRUE;
                }
            }
        }

        int [] temp1 = new int[] {0, 0, 1, -1};
        int [] temp2 = new int[] {1, -1, 0, 0};
        while (!queue.isEmpty()) {
            int size = queue.size();
            // 每一次扩散 相当于所有的0向上下左右走了一步, 所有能被扩散到的点, 都是1
            // 注意是相当于同时扩散, 能被扩散到的距离一定是 + 1
            for (int i = 0; i < size; i ++) {
                int [] origin = queue.poll();
                for (int j = 0; j < 4; j ++) {
                    int targetRow = origin[0] + temp1[j];
                    int targetCol = origin[1] + temp2[j];
                    if (targetRow >=0 && targetRow < matrix.length && targetCol >= 0 && targetCol < matrix[0].length && !visited[targetRow][targetCol]) {
                        distance[targetRow][targetCol] = distance[origin[0]][origin[1]] + 1;
                        visited[targetRow][targetCol] = Boolean.TRUE;
                        queue.offer(new int[] {targetRow, targetCol});
                    }
                }

            }
        }

        return distance;

    }

思路

(1) 目的是寻找1到最近0的距离, 假设我们以1为起点, 通过上下左右四个方向进行寻找, 然后下一轮将涉及到的4个节点添加到队列中, 作为下一轮的起点, 然后下一轮对于每个起点, 再次扩散上下左右, 只到遇到第一个0为止, 扩散的轮数, 就是距离.

但是这样的话, 我每次都只能以1为起点, 然后扩散一遍, 中间存在了很多重复计算根本无法用到, 例如大量的1到1的距离, 能帮助我们什么呢? 并且本身1到1自己的距离, 都没用, 只能通过轮数来计算距离

(2) 但是如果我们以0为起点, 寻找1呢, 根据题意0到0的距离是1, 因此0在扩散一次后, 每个位置(除来本身是0的以外)距离当前0的距离是可以计算得到的, 并且这个距离在一下扩散是可以用到的, 结果可以记录下来, 不用重复计算了. 如果当只有一个0的时候, 那么这个思路就够了.

(3) 如果有多个0的话, 哪个0先扩散就成了问题, 因此可以把所有0视为同一个0, 让大家一起扩散, 这样能够保证每个非0的元素 被扩散到的0, 一定是距离它最近的一个0之一. 因为如果一个1两边都是0, 就算0实际上是先后扩散的, 但是只扩散一步的情况下, 被左边的0扩散到, 和被右边的0扩散到, 结果是一样的.

通过同时扩散的方式, 就无需就最小距离了, 因为能被扩散到的 一定是最小距离