友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

73. 矩阵置零

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

示例 1:

0073 01
输入:matrix =
[
  [1,1,1],
  [1,0,1],
  [1,1,1]
]

输出:
[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]

示例 2:

0073 02
输入:matrix =
[
  [0,1,2,0],
  [3,4,5,2],
  [1,3,1,5]
]

输出:
[
  [0,0,0,0],
  [0,4,5,0],
  [0,3,1,0]
]

提示:

  • m == matrix.length

  • n == matrix[0].length

  • 1 <= m, n <= 200

  • -231 <= matrix[i][j] <= 231 - 1

进阶:

  • 一个直观的解决方案是使用 \(O(mn)\) 的额外空间,但这并不是一个好的解决方案。

  • 一个简单的改进方案是使用 \(O(m + n)\) 的额外空间,但这仍然不是最好的解决方案。

  • 你能想出一个仅使用常量空间的解决方案吗?

思路分析

最简单的办法就是记录出现 0 的行号和列号,最后根据行号和列号设置 0。取巧的办法是把出现 0 的位置在首行和首列标记一下,首行和首列需要首先检查一下是否已经包含 0,最后再单独处理首行和首列。

0073 10
  • 一刷

  • 二刷(路标)

  • 二刷(位元素 )

  • 二刷(头部标记)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    /**
     * Runtime: 1 ms, faster than 100.00% of Java online submissions for Set Matrix Zeroes.
     *
     * Memory Usage: 50.4 MB, less than 5.71% of Java online submissions for Set Matrix Zeroes.
     *
     * @author D瓜哥 · https://www.diguage.com
     * @since 2019-10-27 00:59
     */
    public void setZeroes(int[][] matrix) {
        if (Objects.isNull(matrix) || matrix[0].length == 0) {
            return;
        }
        /**
         * 0 all is 0;
         * 1 row is 0;
         * 2 column is 0;
         * 3 is not 0;
         */
        int flag = 3;
        int value = matrix[0][0];
        if (value == 0) {
            flag = 0;
        }
        int column = matrix.length;
        int row = matrix[0].length;
        for (int i = 0; i < column; i++) {
            for (int j = 0; j < row; j++) {
                if (matrix[i][j] == 0) {
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                    if (i == 0 && j > 0 && flag != 0) {
                        flag = 1;
                    }
                    if (i > 0 && j == 0 && flag != 0) {
                        if (flag == 1) {
                            flag = 0;
                        } else {
                            flag = 2;
                        }
                    }
                }
            }
        }
//        printMatrix(matrix);
        for (int i = 1; i < column; i++) {
            if (matrix[i][0] == 0) {
                Arrays.fill(matrix[i], 0);
            }
        }
        for (int j = 1; j < row; j++) {
            if (matrix[0][j] == 0) {
                for (int i = 0; i < column; i++) {
                    matrix[i][j] = 0;
                }
            }
        }
        if (flag == 0) {
            Arrays.fill(matrix[0], 0);
            for (int i = 0; i < column; i++) {
                matrix[i][0] = 0;
            }
        } else if (flag == 1) {
            Arrays.fill(matrix[0], 0);
        } else if (flag == 2) {
            for (int i = 0; i < column; i++) {
                matrix[i][0] = 0;
            }
        }
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-11-19 20:32
 */
public void setZeroes(int[][] matrix) {
  int m = matrix.length;
  int n = matrix[0].length;
  // 记录 行号和列号,最后按照行号和列号来进行处理
  Set<String> zeros = new HashSet<>();
  for (int r = 0; r < m; r++) {
    for (int c = 0; c < n; c++) {
      if (matrix[r][c] == 0) {
        zeros.add("r" + r);
        zeros.add("c" + c);
      }
    }
  }
  for (int r = 0; r < m; r++) {
    for (int c = 0; c < n; c++) {
      if (zeros.contains("r" + r) || zeros.contains("c" + c)) {
        matrix[r][c] = 0;
      }
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-11-19 21:18
 */
public void setZeroes(int[][] matrix) {
  // 从数中找缺失的数字,使用缺失的数字作为占位符来处理
  // 处理其他太费劲了。而且,细节太多,极易出错。
  int m = matrix.length;
  int n = matrix[0].length;
  int size = m * n % 32 == 0 ? m * n / 32 : m * n / 32 + 1;
  int cap = size * 32;
  // 使用位来标记哪个数字出现过
  int[] data = new int[size];
  Arrays.fill(data, 0);
  for (int[] ints : matrix) {
    for (int r = 0; r < n; r++) {
      int num = ints[r];
      if (num >= cap || num < 0) {
        continue;
      }
      int index = num / 32;
      int rem = num % 32;
      data[index] |= (1 << rem);
    }
  }
  int placeholder = cap + 2;
  for (int i = 0; i < data.length; i++) {
    int bits = data[i];
    for (int j = 0; j < 32; j++) {
      // 第一个未出现的数字就是可用的占位符
      if (((bits >>> j) & 1) == 0) {
        placeholder = i * 32 + j;
        break;
      }
    }
    if (placeholder != cap + 2) {
      break;
    }
  }

  // 先将出现0的行列使用占位符数字标记
  for (int c = 0; c < m; c++) {
    for (int r = 0; r < n; r++) {
      if (matrix[c][r] == 0) {
        for (int ic = 0; ic < m; ic++) {
          if (matrix[ic][r] != 0) {
            matrix[ic][r] = placeholder;
          }
        }
        for (int ir = 0; ir < n; ir++) {
          if (matrix[c][ir] != 0) {
            matrix[c][ir] = placeholder;
          }
        }
      }
    }
  }
  // 再统一修改为 0
  for (int c = 0; c < m; c++) {
    for (int r = 0; r < n; r++) {
      if (matrix[c][r] == placeholder) {
        matrix[c][r] = 0;
      }
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-11-19 22:32
 */
public void setZeroes(int[][] matrix) {
  int m = matrix.length;
  int n = matrix[0].length;
  // 第一列有没有 0
  boolean rowHasZero = false;
  for (int c = 0; c < m; c++) {
    if (matrix[c][0] == 0) {
      rowHasZero = true;
      break;
    }
  }
  // 第一行有没有 0
  boolean colHasZero = false;
  for (int r = 0; r < n; r++) {
    if (matrix[0][r] == 0) {
      colHasZero = true;
    }
  }

  // 将出现的 0 首行和首列标记一下
  for (int c = 1; c < m; c++) {
    for (int r = 1; r < n; r++) {
      if (matrix[c][r] == 0) {
        matrix[c][0] = 0;
        matrix[0][r] = 0;
      }
    }
  }
  // 根据首行和首列来修改为 0
  for (int c = 1; c < m; c++) {
    if (matrix[c][0] == 0) {
      for (int r = 1; r < n; r++) {
        matrix[c][r] = 0;
      }
    }
  }
  for (int r = 1; r < n; r++) {
    if (matrix[0][r] == 0) {
      for (int c = 1; c < m; c++) {
        matrix[c][r] = 0;
      }
    }
  }
  // 最后处理首行和首列
  if (colHasZero) {
    for (int r = 0; r < n; r++) {
      matrix[0][r] = 0;
    }
  }
  if (rowHasZero) {
    for (int c = 0; c < m; c++) {
      matrix[c][0] = 0;
    }
  }
}