来源

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/set-matrix-zeroes/

描述

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

示例 1:
输入:
[
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:
[
[1,0,1],
[0,0,0],
[1,0,1]
]

示例 2:
输入:
[
[0,1,2,0],
[3,4,5,2],
[1,3,1,5]
]
输出:
[
[0,0,0,0],
[0,4,5,0],
[0,3,1,0]
]

进阶:
一个直接的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
你能想出一个常数空间的解决方案吗?

题解

额外存储空间法

  1. class Solution {
  2. public void setZeroes(int[][] matrix) {
  3. int R = matrix.length;
  4. int C = matrix[0].length;
  5. Set<Integer> rowSets = new HashSet<>();
  6. Set<Integer> columnSets = new HashSet<>();
  7. for (int i = 0; i < R; i++) {
  8. for (int j = 0; j < C; j++) {
  9. if (matrix[i][j] == 0) {
  10. rowSets.add(i);
  11. columnSets.add(j);
  12. }
  13. }
  14. }
  15. for (int i = 0; i < R; i++) {
  16. for (int j = 0; j < C; j++) {
  17. if (rowSets.contains(i) || columnSets.contains(j)) {
  18. matrix[i][j] = 0;
  19. }
  20. }
  21. }
  22. }
  23. }

复杂度分析

  • 时间复杂度:73. 矩阵置零(Set Matrix Zeroes) - 图1,其中73. 矩阵置零(Set Matrix Zeroes) - 图273. 矩阵置零(Set Matrix Zeroes) - 图3分别对应行数和列数
  • 空间复杂度:73. 矩阵置零(Set Matrix Zeroes) - 图4

    暴力法

    上述方法使用额外空间去记录需要置零的行号和列号,但其实可以通过修改原始矩阵避免额外空间的消耗。
    循环两遍,第一遍将符合条件的非零元素置为虚拟值(虚拟值的取值依赖于问题约束);第二遍将虚拟值置为零

    1. class Solution {
    2. public void setZeroes(int[][] matrix) {
    3. int MODIFIED = -1000000;
    4. int R = matrix.length;
    5. int C = matrix[0].length;
    6. for (int r = 0; r < R; r++) {
    7. for (int c = 0; c < C; c++) {
    8. if (matrix[r][c] == 0) {
    9. for (int k = 0; k < C; k++) {
    10. if (matrix[r][k] != 0) {
    11. matrix[r][k] = MODIFIED;
    12. }
    13. }
    14. for (int k = 0; k < R; k++) {
    15. if (matrix[k][c] != 0) {
    16. matrix[k][c] = MODIFIED;
    17. }
    18. }
    19. }
    20. }
    21. }
    22. for (int r = 0; r < R; r++) {
    23. for (int c = 0; c < C; c++) {
    24. if (matrix[r][c] == MODIFIED) {
    25. matrix[r][c] = 0;
    26. }
    27. }
    28. }
    29. }
    30. }

    复杂度分析

  • 时间复杂度:73. 矩阵置零(Set Matrix Zeroes) - 图5,其中73. 矩阵置零(Set Matrix Zeroes) - 图673. 矩阵置零(Set Matrix Zeroes) - 图7分别对应行数和列数。尽管这个方法避免了使用额外空间,但是效率很低:当每个元素都为零时,我们需要访问所有的行和列。

  • 空间复杂度:73. 矩阵置零(Set Matrix Zeroes) - 图8

    优化法

    上述暴力法的缺点是存在大量冗余赋值。我们可以用每行和每列的第一个元素作为标记,表示这一行或者这一列是否需要赋零。
    注意点:第一行和第一列的标记位由于会重复,故第一列的标记位使用单独的变量,第一行的标记位使用73. 矩阵置零(Set Matrix Zeroes) - 图9

    1. class Solution {
    2. public void setZeroes(int[][] matrix) {
    3. int R = matrix.length;
    4. int C = matrix[0].length;
    5. boolean isColumn = false;
    6. for (int i = 0; i < R; i++) {
    7. if (matrix[i][0] == 0) isColumn = true;
    8. for (int j = 1; j < C; j++) {
    9. if (matrix[i][j] == 0) {
    10. matrix[i][0] = 0;
    11. matrix[0][j] = 0;
    12. }
    13. }
    14. }
    15. for (int i = 1; i < R; i++) {
    16. for (int j = 1; j < C; j++) {
    17. if (matrix[i][0] == 0 || matrix[0][j] == 0) {
    18. matrix[i][j] = 0;
    19. }
    20. }
    21. }
    22. // 第一行
    23. if (matrix[0][0] == 0) {
    24. for (int j = 0; j < C; j++) {
    25. matrix[0][j] = 0;
    26. }
    27. }
    28. // 第一列
    29. if (isColumn) {
    30. for (int i = 0; i < R; i++) {
    31. matrix[i][0] = 0;
    32. }
    33. }
    34. }
    35. }

    复杂度分析

  • 时间复杂度:73. 矩阵置零(Set Matrix Zeroes) - 图10

  • 空间复杂度:73. 矩阵置零(Set Matrix Zeroes) - 图11