题目链接

01矩阵

题目描述

image.png

解题思路

方法一:多源最短路径

步骤:

  1. 初始化一个队列queue,以及一个dist数组记录每个点的结果值;
  2. 第一次遍历数据,找到所有的0放入到queue中,并将对应位置的dist的值设置为0;
  3. 第二次遍历queue,对每个值进行上下左右四个位置的遍历,并进行dist结果更新;
  4. 继续步骤三,直到清空queue

实现代码:

  1. class Solution {
  2. static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
  3. public int[][] updateMatrix(int[][] matrix) {
  4. int m = matrix.length, n = matrix[0].length;
  5. int[][] dist = new int[m][n];
  6. boolean[][] seen = new boolean[m][n];
  7. Queue<int[]> queue = new LinkedList<int[]>();
  8. // 将所有的 0 添加进初始队列中
  9. for (int i = 0; i < m; ++i) {
  10. for (int j = 0; j < n; ++j) {
  11. if (matrix[i][j] == 0) {
  12. queue.offer(new int[]{i, j});
  13. seen[i][j] = true;
  14. }
  15. }
  16. }
  17. // 广度优先搜索
  18. while (!queue.isEmpty()) {
  19. int[] cell = queue.poll();
  20. int i = cell[0], j = cell[1];
  21. for (int d = 0; d < 4; ++d) {
  22. int ni = i + dirs[d][0];
  23. int nj = j + dirs[d][1];
  24. if (ni >= 0 && ni < m && nj >= 0 && nj < n && !seen[ni][nj]) {
  25. dist[ni][nj] = dist[i][j] + 1;
  26. queue.offer(new int[]{ni, nj});
  27. seen[ni][nj] = true;
  28. }
  29. }
  30. }
  31. return dist;
  32. }
  33. }

方法二:动态规划

记:dist[i][j]表示(i, j)位置的最近0的距离值,对于每个位置而言,他们的移动方向有四种:

  1. 只有 水平向左移动 和 竖直向上移动;
  2. 只有 水平向左移动 和 竖直向下移动;
  3. 只有 水平向右移动 和 竖直向上移动;
  4. 只有 水平向右移动 和 竖直向下移动。

对于每一种移动,都会确定一个方向的最小值,因此,可以进行四次dp状态转移,得到最终的结果数组:

主义四次的顺序:

  1. 水平向左 + 竖直向上
  2. 水平向左 + 竖直向下
  3. 水平向右 + 竖直向上
  4. 水平向右 + 竖直向下

实现代码:

  1. class Solution {
  2. static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
  3. public int[][] updateMatrix(int[][] matrix) {
  4. int m = matrix.length, n = matrix[0].length;
  5. // 初始化动态规划的数组,所有的距离值都设置为一个很大的数
  6. int[][] dist = new int[m][n];
  7. for (int i = 0; i < m; ++i) {
  8. Arrays.fill(dist[i], Integer.MAX_VALUE / 2);
  9. }
  10. // 如果 (i, j) 的元素为 0,那么距离为 0
  11. for (int i = 0; i < m; ++i) {
  12. for (int j = 0; j < n; ++j) {
  13. if (matrix[i][j] == 0) {
  14. dist[i][j] = 0;
  15. }
  16. }
  17. }
  18. // 只有 水平向左移动 和 竖直向上移动,注意动态规划的计算顺序
  19. for (int i = 0; i < m; ++i) {
  20. for (int j = 0; j < n; ++j) {
  21. if (i - 1 >= 0) {
  22. dist[i][j] = Math.min(dist[i][j], dist[i - 1][j] + 1);
  23. }
  24. if (j - 1 >= 0) {
  25. dist[i][j] = Math.min(dist[i][j], dist[i][j - 1] + 1);
  26. }
  27. }
  28. }
  29. // 只有 水平向左移动 和 竖直向下移动,注意动态规划的计算顺序
  30. for (int i = m - 1; i >= 0; --i) {
  31. for (int j = 0; j < n; ++j) {
  32. if (i + 1 < m) {
  33. dist[i][j] = Math.min(dist[i][j], dist[i + 1][j] + 1);
  34. }
  35. if (j - 1 >= 0) {
  36. dist[i][j] = Math.min(dist[i][j], dist[i][j - 1] + 1);
  37. }
  38. }
  39. }
  40. // 只有 水平向右移动 和 竖直向上移动,注意动态规划的计算顺序
  41. for (int i = 0; i < m; ++i) {
  42. for (int j = n - 1; j >= 0; --j) {
  43. if (i - 1 >= 0) {
  44. dist[i][j] = Math.min(dist[i][j], dist[i - 1][j] + 1);
  45. }
  46. if (j + 1 < n) {
  47. dist[i][j] = Math.min(dist[i][j], dist[i][j + 1] + 1);
  48. }
  49. }
  50. }
  51. // 只有 水平向右移动 和 竖直向下移动,注意动态规划的计算顺序
  52. for (int i = m - 1; i >= 0; --i) {
  53. for (int j = n - 1; j >= 0; --j) {
  54. if (i + 1 < m) {
  55. dist[i][j] = Math.min(dist[i][j], dist[i + 1][j] + 1);
  56. }
  57. if (j + 1 < n) {
  58. dist[i][j] = Math.min(dist[i][j], dist[i][j + 1] + 1);
  59. }
  60. }
  61. }
  62. return dist;
  63. }
  64. }