lc542. 01 矩阵 (广度优先搜索、动态规划)

文章介绍了如何使用广度优先搜索(BFS)和动态规划解决LeetCode中的01矩阵问题,目标是找到矩阵中每个1到最近的0的最短距离。BFS方法从所有0出发更新距离,而动态规划则从矩阵的四个角开始递推计算最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:542. 01 矩阵

题解:

一、广度优先搜索

如果从每个1出发,广度优先搜索它临近的0,每一次搜索,只能更新当前1的信息,会比较耗时。因此,我们可以从矩阵中的所有0出发,寻找到每个1的距离,这个方法也称多源广度优先搜索

例如:1、从所有的0出发搜索,找到了5个1(浅黄绿色)(距离为1),再从这5个1出发,到达中间1的位置(距离为2)。

 

第一步从超级源点出发,第二步就能到达矩阵中所有的0,第三步就能到达第一层1(5个)...

具体步骤:

1、初始化输出的距离矩阵dist,所有0位置的距离为0,所有1的距离设为INT_MAX,后面根据广度优先搜索更新结果

2、初始化队列q来存储BFS需要搜索的位置,先将所有0的位置加入q

3、抛出队列中的元素{a,b},搜索它的邻居,如果邻居{i,j}新计算的距离更小dist[a][b] + 1 < dist[i][j],将{i,j}加入队列q中,同时更新d[i][j] = dist[a][b] + 1

class Solution {
public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
        int m = mat.size();
        int n = mat[0].size();
// 1、初始化输出的距离矩阵dist,所有0位置的距离为0,所有1的距离设为INT_MAX,后面根据广度优先搜索更新结果
        vector<vector<int>> dist(m, vector<int>(n, INT_MAX));
// 2、初始化队列q来存储BFS需要搜索的位置,先将所有0的位置加入q
        queue<pair <int, int>> q;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (mat[i][j] == 0){
                    dist[i][j] = 0;
                    q.push({i, j});
                }
            }
        }
// 3、抛出队列中的元素{a,b},搜索它的邻居,如果邻居{i,j}新计算的距离更小dist[a][b] + 1 < dist[i][j],
// 则将{i,j}加入队列q中,同时更新d[i][j] = dist[a][b] + 1
        int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};  // 上下左右
        while (!q.empty()) {
            int a = q.front().first;
            int b = q.front().second;
            q.pop();
            for  (int i = 0; i < 4; ++i) {
                int newR = a + dir[i][0];
                int newC = b + dir[i][1];
                if (newR >=0 && newR < m && newC >=0 && newC < n) {
                    if (dist[a][b] + 1 < dist[newR][newC]) {
                        q.push({newR, newC});
                        dist[newR][newC] = dist[a][b] + 1;
                    }
                }
            }
        }
        return dist;
    }
};

二、动态规划

因此我们分别从四个角开始递推,比如从左上角出发(只有 水平向左移动 和 竖直向上移动)

 

对于另外三种移动方法,我们也可以写出类似的状态转移方程,得到四个 f(i, j)的值,那么其中最小的值就表示位置 (i, j)到最近的 0 的距离。

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

参考:

https://leetcode.cn/problems/01-matrix/solution/01ju-zhen-by-leetcode-solution/

https://leetcode.cn/problems/01-matrix/solution/2chong-bfs-xiang-jie-dp-bi-xu-miao-dong-by-sweetie/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值