题目: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/