力扣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 & 朱律叶

明日香 & 香织

彩叶 & 辉夜

小林 & 托尔

夏纪 & 优子

相关推荐
好悬给我拽开线31 分钟前
ZILOT 论文解析
算法
李剑一1 小时前
别再抬杠,前端岗已经没了!无论前后端,我们最终都要成“全干”工程师
前端·面试
SL_staff1 小时前
私有化低代码:面向强监管行业的可控数字化实践
java·低代码
饮水桶_T2 小时前
JAVA IO流笔记
开发语言·数据结构·算法
Yuzhiyuxia2 小时前
【AI Agent面试系列】AI Agent可观测、评测、安全相关的知识点
人工智能·安全·面试
三翼鸟数字化技术团队2 小时前
高性能存储引擎RocksDB:原理与Java生态实践
java
SL_staff2 小时前
JVS-APS有限产能建模的七个刚性支点:面向产线真实约束的技术实现解析
java·开源·全栈
特立独行的猫A2 小时前
少 3 个环节、少 1 次 ABI、少 3500 行代码:cj-tauri 与 Ionic/Capacitor 的鸿蒙桥接机制对比
java·后端·python
星夜离尘562 小时前
MATLAB 离散数据分箱:半开区间、末端点与计数、加权和、平均
算法·matlab
Pniubi3 小时前
力扣76.最小覆盖子串
算法·leetcode·职场和发展