Leetcode 542:01 矩阵 01 Matrix

简介: 题目: 给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.

题目:

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.

The distance between two adjacent cells is 1.

示例 1:
输入:

0 0 0
0 1 0
0 0 0

输出:

0 0 0
0 1 0
0 0 0

示例 2:
输入:

0 0 0
0 1 0
1 1 1

输出:

0 0 0
0 1 0
1 2 1

注意:

  1. 给定矩阵的元素个数不超过 10000。
  2. 给定矩阵中至少有一个元素是 0。
  3. 矩阵中的元素只在四个方向上相邻: 上、下、左、右。

Note:

  1. The number of elements of the given matrix will not exceed 10,000.
  2. There are at least one 0 in the given matrix.
  3. The cells are adjacent in only four directions: up, down, left and right.

解题思路:

​ 关键字:最近、距离。那肯定是广度优先搜索。类似之前的文章 岛屿数量: https://mp.weixin.qq.com/s/BrlMzXTtZWdB7hRfCKNMoQ

将这个问题转化成图,那就是求每个节点 1 到节点 0 最短的路径是多少。从某个节点开始,上下左右向外扩展,每次扩展一圈距离累加1,如:

输入:
1 1 1
0 1 0
0 0 0

转化成图(Graph),每种颜色代表一个层级:

在这里插入图片描述

这就变成了求某个节点到某个节点的深度了。

所以这道题有两种思路:

  • 以节点1为根节点,求该节点到节点0之间的深度
  • 以节点0为根节点,遇到最近的节点1路径计为1,再次以记录为1的节点为根节点继续向内遍历,遇到原节点1再次累加1并得到路径2,以此类推。。。

两种方法各有优劣,

以0节点为根节点解题,要么开辟一个新的二维数组以记录路径,要么先遍历一遍将所有的节点1的值改为不可能和路径大小重复的值。

以1节点为根节点,那么就要做一些多余的重复遍历。

以0为根节点:

逻辑顺序:

以输入下列二维数组为例:

1 1 1
0 1 1
0 0 1

先把原节点值为1 的节点改为M (路径值不可能达到的值,该题中大于10000即可)

先侵染0节点附近的M节点,0节点加1之后得到1节点

再侵染1节点附近的M节点,1节点加1之后得到2节点

......

在这里插入图片描述

Java:

class Solution {

    public int[][] updateMatrix(int[][] matrix) {
        int row = matrix.length, column = matrix[0].length;
        int[][] neighbors = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};//邻居节点的索引偏移量
        Queue<int[]> queue = new LinkedList<>();//队列
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                if (matrix[i][j] == 0) queue.offer(new int[]{i, j});
                else matrix[i][j] = Integer.MAX_VALUE;//节点值为1的节点改为一个路径不可能达到的值
            }
        }
        while (!queue.isEmpty()) {
            int[] tmp = queue.poll();
            for (int i = 0; i < 4; i++) {
                //得到邻居节点索引
                int x = tmp[0] + neighbors[i][0];
                int y = tmp[1] + neighbors[i][1];
                if (x >= 0 && x < row && y >= 0 && y < column && matrix[tmp[0]][tmp[1]] < matrix[x][y]) {
                    matrix[x][y] = matrix[tmp[0]][tmp[1]] + 1;//该节点的值得到邻居节点的路径值+1
                    queue.offer(new int[]{x, y});
                }
            }
        }
        return matrix;
    }
}

Python3:

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        row, column = len(matrix), len(matrix[0])
        nerghbors = [(0, 1), (0, -1), (1, 0), (-1, 0)]
        queue = collections.deque()
        for i in range(row):
            for j in range(column):
                if matrix[i][j] == 0:
                    queue.append((i, j))
                else:
                    matrix[i][j] = 10001

        while queue:
            x, y = queue.popleft()
            for i, j in nerghbors:
                xx = i + x
                yy = j + y
                if 0 <= xx < row and 0 <= yy < column and matrix[x][y] < matrix[xx][yy]:
                    matrix[xx][yy] = matrix[x][y] + 1
                    queue.append((xx, yy))
                
        return matrix

以1为根节点:

Java:

class Solution {
    public int[][] updateMatrix(int[][] matrix) {
        int row = matrix.length, column = matrix[0].length;
        for (int i = 0; i < row; i++)
            for (int j = 0; j < column; j++)
                if (matrix[i][j] == 1) matrix[i][j] = bfs(matrix, i, j, row, column);
        return matrix;
    }

    private int bfs(int[][] matrix, int i, int j, int row, int column) {
        int count = 0;
        Queue<Integer> queue = new LinkedList<>();
        Set<int[]> set = new HashSet<>();
        queue.add(i * column + j);//记录索引的另一种方法
        while (!queue.isEmpty()) {
            int size = queue.size();
            count += 1;
            for (int k = 0; k < size; k++) {
                int tmp = queue.poll();
                int x = tmp / column, y = tmp % column;//得到索引坐标
                //处理上下左右四个邻居节点,遇到0节点直接返回count路径值
                if (x + 1 < row && !set.contains((x + 1) * column + y)) {
                    if (matrix[x + 1][y] != 0) queue.add((x + 1) * column + y);
                    else return count;
                }
                if (x - 1 >= 0 && !set.contains((x - 1) * column + y)) {
                    if (matrix[x - 1][y] != 0) queue.add((x - 1) * column + y);
                    else return count;
                }
                if (y + 1 < column && !set.contains(x * column + y + 1)) {
                    if (matrix[x][y + 1] != 0) queue.add(x * column + y + 1);
                    else return count;
                }
                if (y - 1 >= 0 && !set.contains(x * column + y - 1)) {
                    if (matrix[x][y - 1] != 0) queue.add(x * column + y - 1);
                    else return count;
                }
            }
        }
        return count;
    }
}

Python3:

class Solution:
    def updateMatrix(self, matrix: List[List[int]]) -> List[List[int]]:
        row, column = len(matrix), len(matrix[0])
        for i in range(row):
            for j in range(column):
                if matrix[i][j] == 1:
                    matrix[i][j] = self.bfs(i, j, matrix, row, column)

        return matrix

    def bfs(self, i: int, j: int, matrix: List[List[int]], row: int, column: int) -> int:
        queue = collections.deque()
        count = 0
        nodeset = set()
        queue.append((i, j))
        while queue:
            size = len(queue)
            count += 1
            for i in range(size):
                x, y = queue.popleft()
                if x + 1 < row and (x + 1, y) not in nodeset:
                    if matrix[x + 1][y] != 0:
                        queue.append((x + 1, y))
                    else:
                        return count
                if x - 1 >= 0 and (x - 1, y) not in nodeset:
                    if matrix[x - 1][y] != 0:
                        queue.append((x - 1, y))
                    else:
                        return count
                if y + 1 < column and (x, y + 1) not in nodeset:
                    if matrix[x][y + 1] != 0:
                        queue.append((x, y + 1))
                    else:
                        return count
                if y - 1 >= 0 and (x, y - 1) not in nodeset:
                    if matrix[x][y - 1] != 0:
                        queue.append((x, y - 1))
                    else:
                        return count
        return count
目录
相关文章
|
3月前
|
存储 算法 NoSQL
LeetCode第73题矩阵置零
文章介绍了LeetCode第73题"矩阵置零"的解法,通过使用矩阵的第一行和第一列作为标记来记录哪些行或列需要置零,从而在不增加额外空间的情况下解决问题。
LeetCode第73题矩阵置零
|
1月前
|
算法 C++
Leetcode第59题(螺旋矩阵2)
这篇文章介绍了解决LeetCode第59题“螺旋矩阵II”的算法,通过C++编程实现按顺时针顺序填充一个n x n的正方形矩阵。
15 0
|
3月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
51 6
|
3月前
|
算法 JavaScript Python
【Leetcode刷题Python】79. 单词搜索和剑指 Offer 12. 矩阵中的路径
Leetcode第79题"单词搜索"的Python解决方案,使用回溯算法在给定的二维字符网格中搜索单词,判断单词是否存在于网格中。
41 4
|
3月前
|
算法 Python
【Leetcode刷题Python】73. 矩阵置零
本文介绍了LeetCode第73题的解法,题目要求在给定矩阵中将所有值为0的元素所在的行和列全部置为0,并提供了一种原地算法的Python实现。
32 0
【Leetcode刷题Python】73. 矩阵置零
|
5月前
|
算法
力扣经典150题第三十七题:矩阵置零
力扣经典150题第三十七题:矩阵置零
33 2
|
5月前
力扣随机一题 6/28 数组/矩阵
力扣随机一题 6/28 数组/矩阵
41 0
|
5月前
|
算法
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
|
5月前
|
算法
【经典LeetCode算法题目专栏分类】【第4期】BFS广度优先算法:单词接龙、最小基因变化、二进制矩阵中的最短路径
【经典LeetCode算法题目专栏分类】【第4期】BFS广度优先算法:单词接龙、最小基因变化、二进制矩阵中的最短路径
|
5月前
|
机器学习/深度学习 算法 数据挖掘
LeetCode题目74:搜索二维矩阵
LeetCode题目74:搜索二维矩阵