题目链接
题目描述
解题思路
方法一:多源最短路径
步骤:
- 初始化一个队列queue,以及一个dist数组记录每个点的结果值;
- 第一次遍历数据,找到所有的0放入到queue中,并将对应位置的dist的值设置为0;
- 第二次遍历queue,对每个值进行上下左右四个位置的遍历,并进行dist结果更新;
- 继续步骤三,直到清空queue
实现代码:
class Solution {
static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public int[][] updateMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] dist = new int[m][n];
boolean[][] seen = new boolean[m][n];
Queue<int[]> queue = new LinkedList<int[]>();
// 将所有的 0 添加进初始队列中
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == 0) {
queue.offer(new int[]{i, j});
seen[i][j] = true;
}
}
}
// 广度优先搜索
while (!queue.isEmpty()) {
int[] cell = queue.poll();
int i = cell[0], j = cell[1];
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;
queue.offer(new int[]{ni, nj});
seen[ni][nj] = true;
}
}
}
return dist;
}
}
方法二:动态规划
记:dist[i][j]表示(i, j)位置的最近0的距离值,对于每个位置而言,他们的移动方向有四种:
- 只有 水平向左移动 和 竖直向上移动;
- 只有 水平向左移动 和 竖直向下移动;
- 只有 水平向右移动 和 竖直向上移动;
- 只有 水平向右移动 和 竖直向下移动。
对于每一种移动,都会确定一个方向的最小值,因此,可以进行四次dp状态转移,得到最终的结果数组:
主义四次的顺序:
- 水平向左 + 竖直向上
- 水平向左 + 竖直向下
- 水平向右 + 竖直向上
- 水平向右 + 竖直向下
实现代码:
class Solution {
static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public int[][] updateMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
// 初始化动态规划的数组,所有的距离值都设置为一个很大的数
int[][] dist = new int[m][n];
for (int i = 0; i < m; ++i) {
Arrays.fill(dist[i], Integer.MAX_VALUE / 2);
}
// 如果 (i, j) 的元素为 0,那么距离为 0
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (matrix[i][j] == 0) {
dist[i][j] = 0;
}
}
}
// 只有 水平向左移动 和 竖直向上移动,注意动态规划的计算顺序
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (i - 1 >= 0) {
dist[i][j] = Math.min(dist[i][j], dist[i - 1][j] + 1);
}
if (j - 1 >= 0) {
dist[i][j] = Math.min(dist[i][j], dist[i][j - 1] + 1);
}
}
}
// 只有 水平向左移动 和 竖直向下移动,注意动态规划的计算顺序
for (int i = m - 1; i >= 0; --i) {
for (int j = 0; j < n; ++j) {
if (i + 1 < m) {
dist[i][j] = Math.min(dist[i][j], dist[i + 1][j] + 1);
}
if (j - 1 >= 0) {
dist[i][j] = Math.min(dist[i][j], dist[i][j - 1] + 1);
}
}
}
// 只有 水平向右移动 和 竖直向上移动,注意动态规划的计算顺序
for (int i = 0; i < m; ++i) {
for (int j = n - 1; j >= 0; --j) {
if (i - 1 >= 0) {
dist[i][j] = Math.min(dist[i][j], dist[i - 1][j] + 1);
}
if (j + 1 < n) {
dist[i][j] = Math.min(dist[i][j], dist[i][j + 1] + 1);
}
}
}
// 只有 水平向右移动 和 竖直向下移动,注意动态规划的计算顺序
for (int i = m - 1; i >= 0; --i) {
for (int j = n - 1; j >= 0; --j) {
if (i + 1 < m) {
dist[i][j] = Math.min(dist[i][j], dist[i + 1][j] + 1);
}
if (j + 1 < n) {
dist[i][j] = Math.min(dist[i][j], dist[i][j + 1] + 1);
}
}
}
return dist;
}
}