lc542. 01 矩阵 (广度优先搜索、动态规划)
题目:
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/