【多源BFS问题】01 矩阵

文章目录

  • [542. 01 矩阵](#542. 01 矩阵)
  • [解题思路:多源`BFS` + 正难则反](#解题思路:多源BFS + 正难则反)

542. 01 矩阵

542. 01 矩阵

​ 给定一个由 01 组成的矩阵 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]]

提示:

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 104
  • 1 <= m * n <= 104
  • mat[i][j] is either 0 or 1.
  • mat 中至少有一个 0

解题思路:多源BFS + 正难则反

​ 首先这里用暴力解法肯定会超时,所以就不讲解了!

​ 然后这是我们遇到的第一道多源最短路问题,会讲的详细一点!前面简介说过,多源 BFS 来解决多源最短路问题 需要满足边权为一 的条件,很明显这道题是符合的,所以按照下面的两步走:

  1. 将所有的源点加入到队列中
  2. 一层一层的往外拓展

​ 但是有一个问题,如果我们按照题目的要求,以值为 1 的元素作为源点的话,会有一个问题,就是当所有的 1 作为源点去向外拓展找到 0 的时候,对于这个 "超级源点" 来说,只知道它本身距离 0 的长度,而并不知道里面每个 1 元素距离 0 的长度,这就麻烦了,如下图所示:

​ 既然遇到这个问题,我们就换个思路,正难则反:以值为 0 的元素作为源点向外拓展更新距离 !为什么这样子可以呢,因为以 0 作为源点的话,我们是知道 0 元素最后的距离其实就是 0 ,而向外拓展每一层又可以更新 1 距离当前的距离,一举两得!

​ 所以我们只需要 创建一个二维数组 distance 表示每个元素距离 0 元素的最近距离 ,然后 0 位置的距离都初始化为 0 ,而将 其它位置的距离都初始化为 -1 即可 ,这样子后面我们也 不需要使用 used 数组 来标记走过的元素了,因为可以通过判断是否为 -1 来决定当前位置是否走过!如下图所示:

​ 之后以 0 为源点向外一层一层的拓展,也就是将 0 位置都入队列,然后进行 bfs 操作,然后下一层的距离就是当前层距离加一了。下图是向外拓展一层的情况:

​ 然后以此类推直到队列中没有节点为止,如下图所示:(红色表示当前队列中的节点,蓝色表示新一层更新的距离)

​ 有了大概的思路,其实代码也不难写,和单源路径其实差不多

cpp 复制代码
class Solution {
private:
    int dx[4] = { 0, 0, -1, 1 };
    int dy[4] = { -1, 1, 0, 0 };
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int m = mat.size(), n = mat[0].size();
        vector<vector<int>> distance(m, vector<int>(n, -1)); // 初始化距离矩阵为-1

        // 正难则反:将0的位置都入队列,并且将其距离设置为0
        queue<pair<int, int>> bfs;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(mat[i][j] == 0)
                {
                    distance[i][j] = 0;
                    bfs.push({i, j});
                }
            }
        }

        while(!bfs.empty())
        {
            // 一层一层往外拓展,更新距离
            int size = bfs.size();
            while(size--)
            {
                auto [x, y] = bfs.front();
                bfs.pop();
                
                for(int i = 0; i < 4; ++i)
                {
                    int newx = x + dx[i], newy = y + dy[i];
                    if(newx >= 0 && newy >= 0 && newx < m && newy < n && distance[newx][newy] == -1)
                    {
                        bfs.push({newx, newy});
                        distance[newx][newy] = distance[x][y] + 1; // 只需要在当前距离上加一即可
                    }
                }
            }
        }
        return distance;
    }
};
相关推荐
磊 子2 分钟前
多继承和多态性
开发语言·c++
AbandonForce3 分钟前
C++11:列表初始化||右值和移动语义||引用折叠和完美转发||可变参数模板||lambda表达式||包装器(function bind)
开发语言·数据结构·c++·算法
khalil10208 分钟前
代码随想录算法训练营Day-50 图论02 | 99.岛屿数量-深搜、99.岛屿数量-广搜 、100.岛屿的最大面积
数据结构·c++·算法·leetcode·深度优先·图论
Brilliantwxx8 分钟前
【C++】模版进阶(特化+分离编译+非类型模版参数)
开发语言·数据结构·c++·算法
Black蜡笔小新9 分钟前
自动化AI算法训练服务器DLTM企业级AI模型工作站构筑企业AI自主可控新模式
人工智能·算法·自动化
bnmoel9 分钟前
数据结构深度剖析链表全集:结构实现、分类与底层原理全解析
c语言·数据结构·算法·链表·双向链表
Languorous.9 分钟前
C++数据结构高阶|跳表(Skip List)深度解析:从原理到手写实现,面试高频考点全覆盖
数据结构·c++·list
许长安11 分钟前
RingBuffer:面向网络编程的环形缓冲区实现
服务器·网络·c++·经验分享·笔记·缓存
坚果派·白晓明18 分钟前
【鸿蒙PC三方库移植适配框架解读系列】第六篇:关键注意事项与最佳实践
c语言·开发语言·c++·华为·harmonyos·开源鸿蒙
郝学胜-神的一滴18 分钟前
中级OpenGL教程 005:为球体&平面注入法线灵魂
c++·unity·图形渲染·three.js·opengl·unreal