73. 矩阵置零

发布于:2025-06-23 ⋅ 阅读:(18) ⋅ 点赞:(0)

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

✅ 解题思路:

这道题的难点是:不能新建一个同样大小的矩阵来标记,否则空间复杂度是 O(m × n)。
为了达到 原地修改O(1) 空间复杂度,我们用 第一行和第一列作为标记空间


🔍 代码

class Solution {
    public void setZeroes(int[][] matrix) {
        int rowCount = matrix.length; // number of rows in the matrix // 行数
        int colCount = matrix[0].length; // number of columns in the matrix // 列数

        boolean firstRowHasZero = false; // flag to check if the first row contains a zero // 第一行是否包含 0
        boolean firstColHasZero = false; // flag to check if the first column contains a zero // 第一列是否包含 0

        // Check if the first row has any zeros // 检查第一行是否有0
        for (int col = 0; col < colCount; ++col) {
            if (matrix[0][col] == 0) {
                firstRowHasZero = true;
                break;
            }
        }

        // Check if the first column has any zeros // 检查第一列是否有0
        for (int row = 0; row < rowCount; ++row) {
            if (matrix[row][0] == 0) {
                firstColHasZero = true;
                break;
            }
        }

        // Use the first row and column as markers.
        // Set matrix[i][0] and matrix[0][j] to 0 if matrix[i][j] is 0
        // 使用第一行和第一列作为标记,如果 matrix[i][j] 为 0,就将 matrix[i][0] 和 matrix[0][j] 设为 0
        for (int row = 1; row < rowCount; ++row) {
            for (int col = 1; col < colCount; ++col) {
                if (matrix[row][col] == 0) {
                    matrix[row][0] = 0;
                    matrix[0][col] = 0;
                }
            }
        }

        // Iterate over the matrix again using the first row and column as reference,
        // and set the elements to 0 accordingly.
        // 再次遍历矩阵,用第一行和第一列做参考,根据标记把对应位置设为 0
        for (int row = 1; row < rowCount; ++row) {
            for (int col = 1; col < colCount; ++col) {
                if (matrix[row][0] == 0 || matrix[0][col] == 0) {
                    matrix[row][col] = 0;
                }
            }
        }

        // Nullify the first row if needed // 如果第一行原本有0,就把整行都设为0
        if (firstRowHasZero) {
            for (int col = 0; col < colCount; ++col) {
                matrix[0][col] = 0;
            }
        }

        // Nullify the first column if needed // 如果第一列原本有0,就把整列都设为0
        if (firstColHasZero) {
            for (int row = 0; row < rowCount; ++row) {
                matrix[row][0] = 0;
            }
        }
    }
}

✨ 总结重点:

步骤 目的
第1步 判断第一行和第一列是否有0,单独记录(因为第一行和列会被当作标记位使用)
第2步 从第二行第二列开始遍历,如果某个位置是0,就在它那一行的最前和那一列的最上标记为0
第3步 再次遍历,根据标记,将该位置设为0
第4步 根据最初记录的标志,最后处理第一行和第一列

这样做的优点是:不使用额外的空间,只在原数组上操作,时间复杂度为 O(m × n),空间复杂度为 O(1)。

🧩 为啥不能直接改?

因为如果你一边遍历一边改,比如刚遇到一个 0,你把那一行一列都变成 0,那么你下一次就可能误以为其他原本不是 0 的地方也要变成 0,逻辑就错了。


✅ 所以我们做了啥?

我们利用第一行和第一列当成“记事本”(占位标记)来“记下”哪一行和哪一列最终需要变成 0

比如,如果我们发现 matrix[2][3] 是 0,我们就做:

matrix[2][0] = 0; // 表示第2行要变成0

matrix[0][3] = 0; // 表示第3列要变成0

🔍 关键代码部分是:

for (int row = 1; row < rowCount; ++row) {

for (int col = 1; col < colCount; ++col) {

// 如果这一行在第一列被标记为0,或者这一列在第一行被标记为0

if (matrix[row][0] == 0 || matrix[0][col] == 0) {

matrix[row][col] = 0; // 就把这个元素设成0 }

} }

✅ 总结:

第一行第一列作为“标记区”是为了记住哪一行/列最终需要清零
在后续再次遍历时,我们通过看:

matrix[row][0] == 0 // 这一行要变0 matrix[0][col] == 0 // 这一列要变0

来决定当前元素是否要变为 0。


网站公告

今日签到

点亮在社区的每一天
去签到