概述
题目链接
- 题目没有需要注意的地方
分析
BFS
因为要求最近距离考虑使用BFS
动态规划
dp[i][j]:mat[i][j]离0最近的距离
d
p
[
i
]
[
j
]
=
{
1
+
m
i
n
(
d
p
[
i
+
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
+
1
]
,
d
p
[
i
]
[
j
−
1
]
)
,
if mat[i][j] = 1
0
if mat[i][j] = 0
dp[i][j] = \begin{cases} 1 + min(dp[i+1][j], dp[i-1][j], dp[i][j+1],dp[i][j-1]), &\text{if mat[i][j] = 1} \\ 0 &\text{if mat[i][j] = 0} \end{cases}
dp[i][j]={1+min(dp[i+1][j],dp[i−1][j],dp[i][j+1],dp[i][j−1]),0if mat[i][j] = 1if mat[i][j] = 0
思路
BFS
- 某点距离0最近的距离,是要考虑它和所有0的情况的
- 所以,我们开始的时候,应该把所有mat[i][j]=0的位置加入队列,然后一圈一圈的往外遍历
动态规划
-
如何初始化部分dp,以支持递推?
-
我们注意到,如果按照上面的递推方程,每个点要考虑4个方向,但是四个邻居到0的最近距离不一定被确定
x x x x ? x x x x 确定中间的dp时,四周邻居的dp不一定都确定
-
所以,我们至少需要遍历四次,分别从四个方向开始,可以确保该方向的邻居到0的最近距离一定存在
-
但是注意到,实际上我们初始化dp可以从左上方到右下方开始,能够确保该点的左边和上边的邻居的dp值一定存在
同理,初始化dp从右下到左上,能够确保该点的下边和右边的邻居的dp值一定存在
-
代码
BFS
class Solution {
public:
int dir[4][2] = {
{1,0},{-1,0},{0,-1},{0,1}
};
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size();
vector<vector<int>> res(m,vector<int>(n,-1)); // 初始化为-1,因为0是有效的值
queue<pair<int,int>> queue_node;
for (int i = 0 ; i < m; ++i)
for (int j = 0; j < n; ++j)
if (mat[i][j] == 0) res[i][j]=0,queue_node.push({i,j}); // 将所有一开始的0进队列
while(!queue_node.empty()) {
int size = queue_node.size();
while(size--) {
auto node = queue_node.front(); queue_node.pop();
for (int i = 0; i < 4; ++i) {
int next_x = node.first + dir[i][0];
int next_y = node.second + dir[i][1];
if (next_x >= 0 && next_x < m &&
next_y >= 0 && next_y < n && res[next_x][next_y] == -1 // 位置合法并且没有访问过
){
res[next_x][next_y] = res[node.first][node.second] + 1; // 相较于原始点,多加了一层,所以加1
queue_node.push({next_x,next_y});
}
}
}
}
return res;
}
};
动态规划
class Solution {
public:
// dp[i][j]:mat[i][j]最近的 0 的距离
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size();
vector<vector<int>> dp(m,vector<int>(n,10002)); // 注意这里初始化的dp的值是一个
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) {
// 每次都会尝试左边和上边的邻居去更新改点dp值
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;
}
};