广度优先搜索
对于矩阵中的每一个元素,如果它的值为 0
,那么离它最近的 0
就是它自己。如果它的值为1
,那么我们就需要找出离它最近的 0
,并且返回这个距离值。那么我们如何对于矩阵中的每一个1
,都快速地找到离它最近的 0
呢?
如果矩阵中只有一个0
,那么我们可以直接使用DFS
深搜递归,或者单源的BFS
广搜队列,找完整个矩阵,更新距离即为最终答案
如图:
初始状态:
_ _ _ _
_ 0 _ _
_ _ _ _
_ _ _ _
其中只有一个 0
,剩余的 1
我们用短横线表示。如果我们从0
开始进行广度优先搜索,那么结果依次为:
也就是说,在广度优先搜索的每一步中,如果我们从矩阵中的位置
x
x
x 搜索到了位置
y
y
y,并且
y
y
y 还没有被搜索过,那么位置
y
y
y 离 0
的距离就等于位置
x
x
x 离 0
的距离加上 1
。
如果有多个0
:
处理的方法很简单:我们在进行广度优先搜索的时候会使用到队列,在只有一个 0
的时候,我们在搜索前会把这个 0
的位置加入队列,才能开始进行搜索;如果有多个 0
,我们只需要把这些 0
的位置都加入队列就行了。
我们还是举一个例子,在这个例子中,有两个 0
:
按照单源0
的方法广搜四个方向:
把更新过的加入广搜队列,重复操作:
这样做为什么是正确的呢?
-
我们需要对于每一个
1
找到离它最近的0
。如果只有一个0
的话,我们从这个0
开始广度优先搜索就可以完成任务了; -
但在实际的题目中,我们会有不止一个
0
。我们会想,要是我们可以把这些0
看成一个整体好了。有了这样的想法,我们可以添加一个「超级零」
,它与矩阵中所有的 0 相连,这样的话,任意一个1
到它最近的0
的距离,会等于这个1
到「超级零」
的距离减去一。由于我们只有一个「超级零」
,我们就以它为起点进行广度优先搜索。这个「超级零」
只和矩阵中的0
相连,所以在广度优先搜索的第一步中,「超级零」
会被弹出队列,而所有的0
会被加入队列,它们到「超级零」
的距离为1
。这就等价于:一开始我们就将所有的0
加入队列,它们的初始距离为0
。这样以来,在广度优先搜索的过程中,我们每遇到一个1
,就得到了它到「超级零」
的距离减去一,也就是 这个1
到最近的0
的距离。
代码(c++)–可作为矩阵多源广搜板子
class Solution {
private:
static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size();
vector<vector<int>> dist(m, vector<int>(n));
vector<vector<int>> seen(m, vector<int>(n));//访问标志
queue<pair<int, int>> q;
// 将所有的 0 添加进初始队列中
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == 0) {//多源进队(板子修改处)
q.emplace(i, j);
seen[i][j] = 1;
}
}
}
// 广度优先搜索
while (!q.empty()) {
auto [i, j] = q.front();
q.pop();
for (int d = 0; d < 4; ++d) {
int ni = i + dirs[d][0];
int nj = j + dirs[d][1];
if (ni >= 0 && ni < m && nj >= 0 && nj < n && !seen[ni][nj]) {//根据题意维护矩阵(板子修改处)
dist[ni][nj] = dist[i][j] + 1;
q.emplace(ni, nj);
seen[ni][nj] = 1;
}
}
}
return dist;
}
};
多源广度搜索的另一题应用:LeetCode994
内容来自LeetCode官方题解,博主稍作修改批注