题目链接:矩阵中的距离
题目:
输入一个由 0、1 组成的矩阵 M,请输出一个大小相同的矩阵 D,矩阵 D 中的每个格子是矩阵 M 中对应格子离最近的 0 的距离。水平或竖直方向相邻的两个格子的距离为 1。假设矩阵 M 中至少有一个 0。
例如,下图 (a) 是一个只包含 0、1 的矩阵 M,它的每个格子离最近的 0 的距离如下图 (b) 的矩阵 D 所示。M[0][0] 等于 0,因此它离最近的 0 的距离是 0,所以 D[0][0] 等于 0。M[2][1] 等于 1,离它最近的 0 的坐标是 (0, 1)、(1, 0)、(1, 2),它们离坐标 (2, 1) 的距离都是 2,所以 D[2][1] 等于 2。
分析:
应用与图相关的算法解决问题的前提是能够找出图中的节点和边。这是一个背景为矩阵的问题,矩阵中的每个格子可以看成图中的一个节点,矩阵中上、下、左、右相邻的格子对应的节点之间有一条边相连。例如,可以将上图 (a) 中的矩阵看成下图所示的图。
这个题目要求计算每个格子离最近的 0 的距离。根据题目的要求,上、下、左、右相邻的两个格子的距离为 1。可以将图看成一个无权图,图中两个节点的距离是连通它们的路径经过的边的数目。由于这个问题与无权图的最近距离相关,因此可以考虑应用广度优先搜索解决。
广度优先搜索需要一个队列。图中的哪些节点可以当作初始节点添加到队列中?这个问题是求每个格子离最近的 0 的距离,因此可以将所有的 0 当作初始节点添加到队列中,然后以值为 0 的节点作为起点做广度优先搜索。当经过 d 步到达某个格子,那么该格子离最近的 0 的距离就是 d。
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int rows = mat.size(), cols = mat[0].size();
vector<vector<int>> dists(rows, vector<int>(cols));
queue<vector<int>> q;
for (int i = 0; i < rows; ++i)
{
for (int j = 0; j < cols; ++j)
{
if (mat[i][j] == 0)
{
dists[i][j] = 0;
q.push(vector<int>{ i, j });
}
else
{
dists[i][j] = INT_MAX;
}
}
}
vector<vector<int>> dirs = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
while (!q.empty())
{
vector<int> coord = q.front();
q.pop();
int dist = dists[coord[0]][coord[1]];
for (vector<int>& dir : dirs)
{
int r = coord[0] + dir[0];
int c = coord[1] + dir[1];
if (r >= 0 && r < rows && c >= 0 && c < cols)
{
if (dists[r][c] > dist + 1)
{
dists[r][c] = dist + 1;
q.push(vector<int>{ r, c });
}
}
}
}
return dists;
}
};