leetcode 542 01矩阵(多源BFS or dp)

题目描述:

  给定一个由0和1组成的矩阵,找出每个元素到最近0的距离,两个相邻元素间的距离为1.

题解:

  BFS:

  先考虑只有一个零的情况,那么只需要从这个零出发BFS更新距离就好。现在矩阵中有多个零,那么我们将这个多个零看作同一层(也可以理解为一个零的集合),然后以这个集合为起点同步BFS即可。举个例子,在这个例子中,有两个 0:  

_ _ _ _
_ 0 _ _
_ _ 0 _
_ _ _ _

我们会把这两个 0 的位置都加入初始队列中,随后我们进行广度优先搜索,找到所有距离为 1 的 1:

_ 1 _ _
1 0 1 _
_ 1 0 1
_ _ 1 _

接着重复步骤,直到搜索完成:

_ 1 _ _         2 1 2 _         2 1 2 3
1 0 1 _   ==>   1 0 1 2   ==>   1 0 1 2
_ 1 0 1         2 1 0 1         2 1 0 1
_ _ 1 _         _ 2 1 2         3 2 1 2

理解清楚BFS的层次遍历方式之后,上述多源BFS理解起来应该不难。代码如下:

class Solution {
public:
    // bfs  dp
    int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    typedef pair<int,int> pii;
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        vector<vector<int>> ans(n,vector<int>(m,INT_MAX/2));
        int vis[n+1][m+1];
        memset(vis,0,sizeof(vis));
        queue<pii> que;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(matrix[i][j] == 0)
                {
                    vis[i][j] = 1;
                    ans[i][j] = 0;
                    que.emplace(i,j);
                }
            }
        }

        while(!que.empty())
        {
            pii now = que.front();
            que.pop();
            for(int i=0;i<4;i++)
            {
                int xx = now.first + dir[i][0];
                int yy = now.second + dir[i][1];
                if(xx < 0 || xx>=n || yy < 0 || yy >=m || vis[xx][yy] == 1) continue;
                ans[xx][yy] = min(ans[xx][yy],ans[now.first][now.second] + 1);
                vis[xx][yy] = 1;
                que.emplace(xx,yy);
            }
        }
        return ans;
    }
};

  DP:

  定义dp[i][j]为位置i,j到最近0的距离。需要梳理清楚的是dp的递推过程,也就是建立一个有序的状态转移。这里$f[x][y]$可以由$f[x][y-1]、f[x][y+1]、f[x-1][y]、f[x+1][y]$四个状态转移而来,那么至少需要遍历两次矩阵,分别为:

  • 只有 水平向左移动 和 竖直向上移动;

  • 只有 水平向右移动 和 竖直向下移动。

  限制好移动的方向之后,状态的转移就比较简单了,详见代码:

  

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        // 初始化动态规划的数组,所有的距离值都设置为一个很大的数
        vector<vector<int>> dist(m, vector<int>(n, INT_MAX / 2));
        // 如果 (i, j) 的元素为 0,那么距离为 0
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == 0) {
                    dist[i][j] = 0;
                }
            }
        }
        // 只有 水平向左移动 和 竖直向上移动,注意动态规划的计算顺序
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i - 1 >= 0) {
                    dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1);
                }
                if (j - 1 >= 0) {
                    dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1);
                }
            }
        }
        // 只有 水平向右移动 和 竖直向下移动,注意动态规划的计算顺序
        for (int i = m - 1; i >= 0; --i) {
            for (int j = n - 1; j >= 0; --j) {
                if (i + 1 < m) {
                    dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1);
                }
                if (j + 1 < n) {
                    dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1);
                }
            }
        }
        return dist;
    }
};

 

posted @ 2020-04-15 10:12  猪突猛进!!!  阅读(203)  评论(0编辑  收藏  举报