542. 01 矩阵
给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。
两个相邻元素间的距离为 1 。
示例 1:
输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
示例 2:
输入:mat = [[0,0,0],[0,1,0],[1,1,1]]
输出:[[0,0,0],[0,1,0],[1,2,1]]
提示:
m == mat.length
n == mat[i].length
1 <= m, n <= 104
1 <= m * n <= 104
mat[i][j] is either 0 or 1.
mat 中至少有一个 0
解题:
这道题目有两种解题思路:
1、BFS(广度优先搜索)
2、DP(动态规划)
这里首先展示第一种做法——广度优先搜索
广度优先搜索关键在于额外拥有一个队列用于存储结点的坐标,步骤如下:
1、首先将所有值为 0 的点存入队列,用于首先进行搜索,并用一个额外的数组标记为已访问
2、每搜索到一个点,就记该结点的步长为 0 到前一个结点的最短步长 + 1,并标记为已访问
(○´・д・)ノ 需要注意的是,这里不用考虑如果有多个 0 都到达这个位置,是否需要取步长的最小值。因为每个结点我们只搜索它上下左右四个点,广度优先搜索保证了首先将距离该轮所有结点步长为 1 的点全部搜索完毕后才会继续搜索下一轮结点。
代码如下:
const int dx[4] = {0, 0,-1, 1};
const int dy[4] = {1,-1, 0, 0};
int n, m;
int** updateMatrix(int** mat, int matSize, int* matColSize, int* returnSize, int** returnColumnSizes){
n = matSize, m = matColSize[0];
*returnSize = n;
*returnColumnSizes = malloc(sizeof(int*)*n);
int** isvisit = (int**)malloc(sizeof(int*)*n);
for(int i = 0; i < n; i++){
isvisit[i] = (int*)calloc(m, sizeof(int));
(*returnColumnSizes)[i] = m;
}
int** queue = (int**)malloc(sizeof(int*)*m*n);
int x = 0; // 用于跟随队列
// 首先在队列中放入所有 0 的位置
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(mat[i][j] == 0){
queue[x] = (int*)malloc(sizeof(int)*2);
queue[x][0] = i, queue[x++][1] = j;
isvisit[i][j] = 1; // 标记为已访问
}
}
}
int loc = 0; // 记录此时已经取到的位置,取过的点将不再访问
while(loc < x){
int i = queue[loc][0], j = queue[loc++][1]; // 相当于队列poll()的作用
for(int d = 0; d < 4; d++){ // 遍历上下左右四个方向
int new_x = i + dx[d], new_y = j + dy[d];
if(new_x >= 0 && new_x < n && new_y >= 0 && new_y < m && !isvisit[new_x][new_y]){
mat[new_x][new_y] = mat[i][j] + 1; // 直接在原指针上操作,当前步长 = 前一步长 + 1
queue[x] = (int*)malloc(sizeof(int)*2);
queue[x][0] = new_x, queue[x++][1] = new_y; // 用于下一轮的处理
isvisit[new_x][new_y] = 1; // 标记为已访问
}
}
}
return mat;
}