leetcode 542 01矩阵

这篇博客探讨了LeetCode中的542题,即如何找出01矩阵中每个元素到最近的0的距离。作者提供了两种解法:一种是使用宽度优先搜索(BFS),另一种是动态规划(DP)。在BFS解法中,通过改变矩阵元素的值来避免重复访问。而在DP解法中,通过两遍扫描矩阵,分别计算上边和左边,以及右边和下边的最小距离。易错点在于初始化距离为INT_MAX-1以防止溢出。
摘要由CSDN通过智能技术生成

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

两个相邻元素间的距离为 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. 矩阵中的元素只在四个方向上相邻: 上、下、左、右。

 

解法一:bfs

将所有的0都加入队列,1全部改为-1,这个为了防止和后面冲突,后面所有整数表示到0的最近的距离。

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m=matrix.size(),n=matrix[0].size();
        queue<pair<int,int>> q;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(!matrix[i][j])q.push(make_pair(i,j));
                else matrix[i][j]=-1;
            }
        
        while(!q.empty()){
            pair<int,int> t=q.front();q.pop();
            int x=t.first,y=t.second;
            int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
            for(int i=0;i<4;i++){
                int nx=x+dir[i][0];
                int ny=y+dir[i][1];
                if(nx>=0&&nx<m&&ny>=0&&ny<n&&matrix[nx][ny]==-1){
                    matrix[nx][ny]=matrix[x][y]+1;
                    q.push(make_pair(nx,ny));
                }
            }
        }
        return matrix;
    }
};

看来对bfs的领悟还是不够透彻,最基本的bfs是二叉树的层序遍历,这种bfs最简单,从上而下,不用考虑会不会遇到调用同一个节点的问题;进阶一点的就是图的bfs,这需要解决上面提到的问题,目前最常用的解决方法就是数字值限制,只允许某个特定的值,调用后改为另一个值。这样访问循序就变成了二叉树一样的从上到下的单射。还有一种方法就是设置访问数组(少)

 

解法二:dp

这题的dp办法其实是最最简洁的。对于每个点,值为0距离为0,值不为0,则值为上下左右点最小的那个加1,我第一遍写的时候其实想到了这个方法,但是不知道没有计算出来的点如何处理。查资料后发现可以用两遍扫描法解决问题。

第一遍扫描左边和上面的点,取最小值加1
第二遍倒过来从右下角开始扫描,取右边和下面点的最小值加1

易错点:初始化为INT_MAX
分析:假如一个3*3的矩阵,只有右下角为0,其余为1。在第一遍扫描的过程中,[1,1]点左上都是INT_MAX,加1的过程会溢出,所以初始化为INT_MAX-1,不用担心溢出,取最小值永远也达不到INT_MAX

 

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m=matrix.size(),n=matrix[0].size();
        vector<vector<int>> res=matrix;
        for(int i=0;i<m;i++)for(int j=0;j<n;j++)if(res[i][j])res[i][j]=INT_MAX-1;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(res[i][j]){
                    if(i>0)res[i][j]=min(res[i][j],res[i-1][j]+1);
                    if(j>0)res[i][j]=min(res[i][j],res[i][j-1]+1);
                }
            }
        for(int i=m-1;i>=0;i--)
            for(int j=n-1;j>=0;j--){
                if(res[i][j]){
                    if(i<m-1)res[i][j]=min(res[i][j],res[i+1][j]+1);
                    if(j<n-1)res[i][j]=min(res[i][j],res[i][j+1]+1);
                }
            }
        return res;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值