leetcode 542. 01 矩阵(BFS || Dp)

542. 01 矩阵

难度中等158

给定一个由 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. 矩阵中的元素只在四个方向上相邻: 上、下、左、右

思路一: 这道题属于 边长为1 的最短路径问题 ,从每个 0出发,考虑 0 到 1 的距离,从 0 出现的位置 进行BFS(需要对每个位置 0 都进行这样的操作,),这样明显超时!!!!

 这里有个小优化的思路:利用Dijkstra的思想!!!

     把所有的 0 的压进队列,然后选择队列外的点,如果距离比之前的小 ,就更新,进栈,直至距离不再更新 也不会入栈

先放一下TLE代码

class Solution {
public:
    struct node{
        int x,y;
        int floor;
    };
    int m,n;
    bool Judge(int x,int y){
        if(x>=0&&x<m&&y>=0&&y<n){
            return true;
        }
        return false;
    }
    
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        m = matrix.size();
        n = matrix[0].size();
        vector<vector<int>> ans(m,vector<int>(n,0x3f3f3f3f));
        int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(matrix[i][j]==0){//进行BFS
                    vector<vector<bool>> flag(m,vector<bool>(n,0));  //一开始都是 0没有访问
                    queue<node> q;
                    ans[i][j] = 0; // 是0 的话置 0
                    node tmp;
                    tmp.x = i;
                    tmp.y = j;
                    tmp.floor = 0;
                    // cout<<"i "<<i<<" j "<<j<<endl;
                    q.push(tmp);
                    flag[i][j] = 1;
                    while(!q.empty()){
                        node now = q.front();
                        q.pop();
                        for(int i=0;i<4;i++){
                            int tmpx = now.x+dir[i][0];
                            int tmpy = now.y+dir[i][1];
                            if(Judge(tmpx,tmpy)&&matrix[tmpx][tmpy]==1&&flag[tmpx][tmpy]==0){
                                tmp.x = tmpx;
                                tmp.y = tmpy;
                                tmp.floor = now.floor+1;
                                flag[tmpx][tmpy] = 1;
                                // cout<<" tmp.x "<< tmp.x<<"tmp.y "<<tmp.y<<"tmp.floor  "<<tmp.floor<<endl;
                                q.push(tmp);
                                if(tmp.floor<ans[tmpx][tmpy])
                                    ans[tmpx][tmpy] = tmp.floor;
                            }
                        }
                    }
                }

            }
            return ans;
    }
};

Ac代码  

class Solution {
public:
    struct node{
        int x,y;
        int floor;
    };
   
    bool Judge(int x,int y){
        if(x>=0&&x<m&&y>=0&&y<n){
            return true;
        }
        return false;
    }
    int m,n;
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        m = matrix.size();
        n = matrix[0].size();
        vector<vector<int>> ans(m,vector<int>(n,0x3f3f3f3f));
        int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
        queue<node> q;
        node tmp;
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(matrix[i][j]==0){
                    tmp.x = i;
                    tmp.y = j;
                    tmp.floor = 0;  
                    ans[i][j] = 0;
                    q.push(tmp);
                }
            }
        while(!q.empty()){
            node now = q.front();
            q.pop();
            for(int i=0;i<4;i++){
                int tmpx = now.x+dir[i][0];
                int tmpy = now.y+dir[i][1];
                if(Judge(tmpx,tmpy)&&matrix[tmpx][tmpy]==1){
                    tmp.x = tmpx;
                    tmp.y = tmpy;
                    tmp.floor = now.floor+1;
                    if(ans[tmpx][tmpy]>tmp.floor){
                        q.push(tmp);
                        ans[tmpx][tmpy]=tmp.floor;
                    }
                }
            }
        }   
        return ans;
    }
};

动态规划思路:  (我觉得这个解释很 玄学!!!!)

对于一个节点来说,它到 0 的距离可以通过邻居的最近距离计算,在这种情况下最近距离是邻居的距离 + 1。因此,这就让我们想到了动态规划!

对于每个 1,到 0 的最短路径可能从任意方向。所以我们需要检查所有 4 个方向。在从上到下的迭代中,我们需要检查左边和上方的最短路径;我们还需要另一个从下往上的循环,检查右边和下方的方向。

算法

从上至下、从左至右迭代整个矩阵:

更新

\text{dist}[i][j]=\min(\text{dist}[i][j],\min(\text{dist}[i][j-1],\text{dist}[i-1][j])+1)dist[i][j]=min(dist[i][j],min(dist[i][j−1],dist[i−1][j])+1)

最近距离考虑上方邻居和左侧邻居距离 + 1,这在前面的迭代中已经计算完成。

从下到上、从右至左迭代整个矩阵:

更新

\text{dist}[i][j]=\min(\text{dist}[i][j],\min(\text{dist}[i][j+1],\text{dist}[i+1][j])+1)dist[i][j]=min(dist[i][j],min(dist[i][j+1],dist[i+1][j])+1)

最近距离考虑下方邻居和右侧邻居距离 + 1,这在前面的迭代中已经计算完成。

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();

        vector<vector<int> > dp(m,vector<int>(n,0x3f3f3f3f));
        for(int i=0;i<m;i++)
            for(int j=0;j<n;j++){
                if(matrix[i][j]==0){
                    dp[i][j] = 0;
                    continue;
                }
                else{
                    if(i>0)
                        dp[i][j] = min(dp[i][j],dp[i-1][j]+1);
                    if(j>0)
                        dp[i][j] = min(dp[i][j],dp[i][j-1]+1); 
                }
            }
        for(int i=m-1;i>=0;i--)
            for(int j=n-1;j>=0;j--){
                if(matrix[i][j]==0){
                    dp[i][j] = 0;
                    continue;
                }
                else{
                    if(i<m-1)
                        dp[i][j] = min(dp[i][j],dp[i+1][j]+1);
                    if(j<n-1)
                        dp[i][j] = min(dp[i][j],dp[i][j+1]+1);
                }
            }
        return dp;
    }
};
发布了124 篇原创文章 · 获赞 47 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/ludan_xia/article/details/105136078