LC:542 01矩阵

560 阅读3分钟

我的思路跟ac代码是一样的,但是在处理队列,入点进去的时候就有问题了。所以20个测试用例只过了19个。

解决

首先你要知道这道题是解决什么问题,用什么方法。它是解决路径问题,多个起点,终点也不定。所以用bfs。

而我的问题就出现在入对的点不对,应该是起点入队,也就是0入队,到达1的时候就是最短路径bfs,或者说是0周围的1入队,这样一个思路。要思考是谁去入队才能遍历对。

bfs模板

bfs有两个模板,如下:

BFS 使用队列,把每个还没有搜索到的点依次放入队列,然后再弹出队列的头部元素当做当前遍历点。BFS 总共有两个模板:

如果不需要确定当前遍历到了哪一层,BFS 模板如下。

    cur = queue.pop()
    for 节点 in cur的所有相邻节点:
        if 该节点有效且未访问过:
            queue.push(该节点)
    

如果要确定当前遍历到了哪一层,BFS 模板如下。 这里增加了 level 表示当前遍历到二叉树中的哪一层了,也可以理解为在一个图中,现在已经走了多少步了。size 表示在当前遍历层有多少个元素,也就是队列中的元素数,我们把这些元素一次性遍历完,即把当前层的所有元素都向外走了一步。

while queue 不空:
    size = queue.size()
    while (size --) {
        cur = queue.pop()
        for 节点 in cur的所有相邻节点:
            if 该节点有效且未被访问过:
                queue.push(该节点)
    }
    level ++;

代码

bfs解法,用时会较长

class Solution {
    class pair {
        int x, y;
        public pair(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
    int[] dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
    public int[][] updateMatrix(int[][] mat) {
        ArrayDeque<pair> q = new ArrayDeque<>();
        int n = mat.length, m = mat[0].length;
        int[][] ans = new int[n][m];
        for(int i = 0;i < n;i ++) {
            for(int j = 0;j < m;j ++) {
                if(mat[i][j] == 0) {
                    q.offer(new pair(i, j));
                }
            }
        }
        while(!q.isEmpty()) {
            pair p = q.poll();
            int x = p.x;
            int y = p.y;
            for(int i = 0;i < 4;i ++) {
                int nx = x + dx[i], ny = y + dy[i];
                if(nx < 0 || ny < 0 || nx >= n || ny >= m
                || mat[nx][ny] == 0 || ans[nx][ny] != 0) continue;
                ans[nx][ny] = ans[x][y] + 1;
                q.offer(new pair(nx, ny));
            }
        }
        return ans;
    }
}

动态规划解法,很漂亮的写法;

class Solution {
    public int[][] updateMatrix(int[][] mat) {
        int n = mat.length;
        int m = mat[0].length;
        // 初始化距离矩阵,将非零元素距离初始化为一个较大的值
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                mat[i][j] = mat[i][j] == 0 ? 0 : Integer.MAX_VALUE / 2;
            }
        }
        // 从左上角开始,从上到下,从左到右地更新距离矩阵
        // 先从左上到右下遍历,再从右下到左上遍历,确保更新的距离是最小的
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (i > 0) {
                    mat[i][j] = Math.min(mat[i][j], mat[i - 1][j] + 1);
                }
                if (j > 0) {
                    mat[i][j] = Math.min(mat[i][j], mat[i][j - 1] + 1);
                }
            }
        }
        for (int i = n - 1; i >= 0; i--) {
            for (int j = m - 1; j >= 0; j--) {
                if (i < n - 1) {
                    mat[i][j] = Math.min(mat[i][j], mat[i + 1][j] + 1);
                }
                if (j < m - 1) {
                    mat[i][j] = Math.min(mat[i][j], mat[i][j + 1] + 1);
                }
            }
        }
        return mat;
    }
}