LeetCode-打卡题(4.15)01矩阵

写在前面

第一次特别写一下leetcode的打卡题,因为今天的打卡题还挺不错的,练习了bfs和简单的dp。

542. 01 矩阵

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

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

示例 1:

输入:

0 0 0

0 1 0

0 0 0

输出:

0 0 0

0 1 0

0 0 0

注意:

给定矩阵的元素个数不超过 10000。

给定矩阵中至少有一个元素是 0。

矩阵中的元素只在四个方向上相邻: 上、下、左、右。

BFS

有两种思路:

  1. 找到1之后,去找0,然后算出最小的距离。
  2. 找到0,开始扩散,算出所有1到这个0的距离,记录最小值。

两种思路都可以算出答案,但是第一种方法从复杂度上来看明显有点高,所以这里我们采用第二种思路。

假设有这样一个矩阵
_ _ _ _
_ 0 _ _
_ _ _ _
_ _ _ _
只有一个0,我们从这个开始广度优先搜索,可以得到以下结果:
bfs1
然后我们再维护一个queue,一开始把所有0的xy坐标放进去,然后bfs的过程中,节点距离更新的坐标也放进去,然后bfs就行了。

代码:

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        if(matrix.empty()) return matrix;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<int>> res(m,vector<int>(n,INT_MAX-1));
        vector<pair<int,int>> dir = {{0,1},{0,-1},{1,0},{-1,0}};//方向数组
        queue<pair<int,int>> q;//保存节点的队列
        for(int i=0; i<m; ++i)
            for(int j=0; j<n; ++j){
                if(matrix[i][j]==0){//找0
                    res[i][j] = 0;
                    q.push({i,j});
                }
            }
        while(!q.empty()){
            auto tmp = q.front();
            q.pop();
            for(int i=0; i<4; ++i){
                int x = tmp.first + dir[i].first;
                int y = tmp.second + dir[i].second;
                if(x>=0 && y>=0 && x<m && y<n && res[x][y]>res[tmp.first][tmp.second]+1){//BFS
                    res[x][y] = res[tmp.first][tmp.second] + 1;
                    q.push({x,y});
                }
            }
        }
        return res;
    }
};

dp

这道题用dp其实比BFS要简介非常多,不管是思路还是代码,回到上一个解法的思路1,我们从一个1开始找0的话,有四种方向:

  1. 只有 水平向左移动 和 竖直向上移动;
  2. 只有 水平向左移动 和 竖直向下移动;
  3. 只有 水平向右移动 和 竖直向上移动;
  4. 只有 水平向右移动 和 竖直向下移动。

然后其实上一个解法的BFS里面,已经包含了我们需要的转移方程:

res[x][y]>res[tmp.first][tmp.second]+1

换成dp的话,转移方程就是这样的:
转移方程
然后分别计算4个方向就行了。

扫描二维码关注公众号,回复: 11149842 查看本文章

代码:

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> dp(m, vector<int>(n, INT_MAX-1));
        for (int i=0; i<m; ++i) {
            for (int j=0; j<n; ++j) {
                if (matrix[i][j] == 0) {
                    dp[i][j] = 0;
                }
            }
        }
        // 只有 水平向左移动 和 竖直向上移动
        for (int i=0; i<m; ++i) {
            for (int j=0; j<n; ++j) {
                if (i-1 >= 0) {
                    dp[i][j] = min(dp[i][j], dp[i-1][j]+1);
                }
                if (j-1 >= 0) {
                    dp[i][j] = min(dp[i][j], dp[i][j-1]+1);
                }
            }
        }
        // 只有 水平向左移动 和 竖直向下移动
        for (int i=m-1; i>=0; --i) {
            for (int j=0; j<n; ++j) {
                if (i+1<m) {
                    dp[i][j] = min(dp[i][j],dp[i+1][j]+1);
                }
                if (j-1>=0) {
                    dp[i][j] = min(dp[i][j],dp[i][j-1]+1);
                }
            }
        }
        // 只有 水平向右移动 和 竖直向上移动
        for (int i=0; i<m; ++i) {
            for (int j=n-1; j>=0; --j) {
                if (i-1>=0) {
                    dp[i][j] = min(dp[i][j],dp[i-1][j]+1);
                }
                if (j+1<n) {
                    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 (i+1<m) {
                    dp[i][j] = min(dp[i][j],dp[i+1][j]+1);
                }
                if (j+1<n) {
                    dp[i][j] = min(dp[i][j],dp[i][j+1]+1);
                }
            }
        }
        return dp;
    }
};

dp小优化

其实通过手动模拟dp过程可以发现,没必要算四个方向,只需要两个方向就够了:

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

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

代码:

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> dp(m, vector<int>(n, INT_MAX-1));
        for (int i=0; i<m; ++i) {
            for (int j=0; j<n; ++j) {
                if (matrix[i][j] == 0) {
                    dp[i][j] = 0;
                }
            }
        }
        // 只有 水平向左移动 和 竖直向上移动
        for (int i=0; i<m; ++i) {
            for (int j=0; j<n; ++j) {
                if (i-1 >= 0) {
                    dp[i][j] = min(dp[i][j], dp[i-1][j]+1);
                }
                if (j-1 >= 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 (i+1<m) {
                    dp[i][j] = min(dp[i][j],dp[i+1][j]+1);
                }
                if (j+1<n) {
                    dp[i][j] = min(dp[i][j],dp[i][j+1]+1);
                }
            }
        }
        return dp;
    }
};
原创文章 23 获赞 41 访问量 3978

猜你喜欢

转载自blog.csdn.net/u011708337/article/details/105528717