力扣73矩阵置零

73. 矩阵置零 - 力扣(LeetCode)

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

示例 1:

**输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]

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

示例 2:

输入: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(_m__n_) 的额外空间,但这并不是一个好的解决方案。
  • 一个简单的改进方案是使用 O(_m_ + _n_) 的额外空间,但这仍然不是最好的解决方案。
  • 你能想出一个仅使用常量空间的解决方案吗?

方法一:最暴力的解法(非原地)

直接遍历数组,遇到0就再分别遍历行和列。

问题:遇到0之后,将其所在行和列的所有元素都置0,后续遍历到"原本为1但被置0"的格子,会误判为该格子原本就是0,进而导致将该格子行列所在元素错误地置0

解决方法:使用一个flag数组记录matrix原本的模样,if条件中只需判断flag中该位置是否为0即可

代码:

java 复制代码
class Solution {
    public void setZeroes(int[][] matrix) {
        int row = matrix.length;
        int col = matrix[0].length;
        int[][] flag = new int[row][];
        for(int i=0;i<row;i++) {
            flag[i] = matrix[i].clone();
        }
        for(int i=0;i<row;i++) {
            for(int j=0;j<col;j++) {
                if(flag[i][j] == 0) {
                    for(int m=0;m<col;m++) {
                        matrix[i][m] = 0;
                    }
                    for(int n=0;n<row;n++) {
                        matrix[n][j] = 0;
                    }
                }
            }
        }
    }
}

因为时间问题,就没写Go/Python/C++版本了,后续的文章主要都是Java/Go/Python版本

时间复杂度:

  • 最好情况:矩阵全为1,O(mn)
  • 最坏情况:矩阵全为0,O(mn(m+n))
  • 其中m、n分别为矩阵的行数与列数

方法二:使用额外数组记录该行/列是否含0(非原地)

使用一个长为row的布尔数组 rowHasZero[] 记录第 i 行是否含0,如果含0,rowHasZero[i] = true

列同理

判断完行列是否含0后,再次遍历matrix,如果 rowHasZero/colHasZero 为true,就把该行/列的所有元素都置0

java 复制代码
class Solution {
    public void setZeroes(int[][] matrix) {
        int row = matrix.length;
        int col = matrix[0].length;
        boolean rowHasZero[] = new boolean[row];
        boolean colHasZero[] = new boolean[col];
        for(int i=0;i<row;i++) {
            for(int j=0;j<col;j++) {
                if(matrix[i][j] == 0) {
                    rowHasZero[i] = true;
                    colHasZero[j] = true;
                }
            }
        }

        for(int i=0;i<row;i++) {
            for(int j=0;j<col;j++) {
                if(rowHasZero[i] || colHasZero[j]) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

方法三:用行头/列头代替两个HasZero数组(原地)

如果这一行有0,那么标记行头为0,后续置0时通过行头即可判断是否要将该行全部置0,列同理

问题:

考虑第一行全为1,第一列含0的矩阵,例如:

复制代码
1 1 1
1 1 1
0 1 1

行列判断完后,变为:

复制代码
0 1 1
1 1 1
0 1 1

此时开始置0,会误判为第一行有0,因为(0,0)是第一行和第一列的交点,所以这个位置为0无法判断究竟是行要置0还是列要置0,因此第一行和第一列需要用两个单独的布尔变量去判断是否含0,最后再分别处理

java 复制代码
class Solution {
    public void setZeroes(int[][] matrix) {
        int row = matrix.length;
        int col = matrix[0].length;
        //使用行头和列头记录是否含0
        boolean firstRowHasZero = false;
        boolean firstColHasZero = false;
        for(int x : matrix[0]) {
            if(x == 0) {
                firstRowHasZero = true;
                break;
            }
        }
        for(int i=0;i<row;i++) {
            if(matrix[i][0] == 0) {
                firstColHasZero = true;
                break;
            }
        }

        for(int i=1;i<row;i++) {
            for(int j=1;j<col;j++) {
                if(matrix[i][j] == 0) {
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
            }
        }

        for(int i=1;i<row;i++) {
            for(int j=1;j<col;j++) {
                if(matrix[i][0] == 0 || matrix[0][j] == 0) {
                    matrix[i][j] = 0;
                }
            }
        }

        if(firstRowHasZero) {
            Arrays.fill(matrix[0],0);
        }
        if(firstColHasZero) {
            for(int[] r : matrix) {
                r[0] = 0;
            }
        }
    }
}

结语

本文含0量极高,那么以下cp中究竟谁是0呢?

千束 & 泷奈

伞哥 & 小肥宅

罗mio & 朱律叶

明日香 & 香织

彩叶 & 辉夜

小林 & 托尔

夏纪 & 优子

相关推荐
AIGS0011 小时前
企业AI落地:从RAG到AgentRAG的技术跃迁
java·人工智能·人工智能ai大模型应用
Tairitsu_H1 小时前
[LC优选算法#18] 前缀和 | 除⾃⾝以外数组的乘积 | 和为K的⼦数组 | 和可被K整除的⼦数组
算法·前缀和·哈希算法
2601_962341302 小时前
计算机毕业设计之jsp考研在线复习平台
java·大数据·开发语言·hadoop·python·考研·课程设计
凯瑟琳.奥古斯特2 小时前
力扣1008:前序重建BST
开发语言·c++·算法·leetcode·职场和发展
huangjiazhi_2 小时前
纯C++实现ini文件操作
java·后端·spring
zhixingheyi_tian2 小时前
JVM 之 GCLocker
java·jvm
码哥字节2 小时前
把 Cursor 的烂输出变成好代码,这 10 个 Prompt 改造让我省了 80% 改稿时间
java·ai编程工具·cursor 配置·prompt 技巧
2503_931712482 小时前
10m/s超高速电梯:西奥XO-NEWIII如何树立行业速度标杆
java·大数据·数据库
aqiu1111113 小时前
【算法日记 13】LeetCode 49. 字母异位词分组:哈希表的进阶“降维打击”
算法·leetcode·散列表