力扣hot100-73.矩阵置零-标记数组详解

LeetCode 73. 矩阵置零:标记数组详解

1. 这道题属于什么算法思想

这题主要归类为:

text 复制代码
矩阵 / 标记数组 / 两阶段处理

核心不是立刻把某一行或某一列改成 0,而是:

text 复制代码
第一阶段:记录哪些行、哪些列需要置零。
第二阶段:根据记录统一置零。

这样可以避免"后来写进去的 0 被误认为原始 0"而发生错误扩散。

题目进阶要求使用原地算法,但本文主解法采用更直观的:

text 复制代码
O(m + n) 额外空间标记数组版本。

它能正确通过题目结果校验,时间复杂度同样是 O(m * n);区别只是没有满足进阶的 O(1) 额外空间要求。

2. 这道题到底在问什么

题目给定一个 m x n 矩阵:

text 复制代码
如果某个元素是 0,就把它所在的整行和整列全部置为 0。

例如:

text 复制代码
matrix =
[
  [1, 1, 1],
  [1, 0, 1],
  [1, 1, 1]
]

原始 0 位于:

text 复制代码
第 1 行、第 1 列。

因此答案应为:

text 复制代码
[
  [1, 0, 1],
  [0, 0, 0],
  [1, 0, 1]
]

3. 为什么不能边扫描边直接置零

最容易想到的做法是:

text 复制代码
扫描到一个 0,就立刻把对应行和列全部改为 0。

这个做法会出错。

仍然使用刚才的例子:

text 复制代码
[
  [1, 1, 1],
  [1, 0, 1],
  [1, 1, 1]
]

扫描到中间的原始 0 后,立刻清零第 1 行、第 1 列,矩阵会暂时变成:

text 复制代码
[
  [1, 0, 1],
  [0, 0, 0],
  [1, 0, 1]
]

但此时:

text 复制代码
matrix[0][1] 也变成了 0。

它不是原矩阵中的 0,只是我们为了答案新写进去的 0

如果后续扫描又把它误认为原始 0,就会继续清零第 0 行,错误会扩散。

因此必须做到:

text 复制代码
先完整读取原始 0 的位置。
再统一修改矩阵。

4. 用 rowZero 和 colZero 分别记录行、列

创建两个布尔数组:

java 复制代码
boolean[] rowZero = new boolean[m];
boolean[] colZero = new boolean[n];

它们的含义是:

text 复制代码
rowZero[i] == true:第 i 行原本出现过 0,最终整行需要置零。
colZero[j] == true:第 j 列原本出现过 0,最终整列需要置零。

第一遍扫描矩阵时,发现:

text 复制代码
matrix[i][j] == 0

只做记录:

java 复制代码
rowZero[i] = true;
colZero[j] = true;

不要修改 matrix

这样第一阶段结束后,rowZerocolZero 保存的仍然完全是"原始 0"带来的影响。

5. 用示例完整推导

text 复制代码
matrix =
[
  [1, 1, 1],
  [1, 0, 1],
  [1, 1, 1]
]

矩阵有:

text 复制代码
m = 3 行
n = 3 列

初始化:

text 复制代码
rowZero = [false, false, false]
colZero = [false, false, false]

第一阶段扫描时,发现:

text 复制代码
matrix[1][1] == 0

记录:

text 复制代码
rowZero[1] = true
colZero[1] = true

扫描结束:

text 复制代码
rowZero = [false, true, false]
colZero = [false, true, false]

第二阶段重新遍历每个位置。

对于 matrix[i][j],只要:

text 复制代码
rowZero[i] == true 或 colZero[j] == true

就将它置为 0

例如:

text 复制代码
matrix[0][1]:colZero[1] 为 true,所以置 0。
matrix[1][0]:rowZero[1] 为 true,所以置 0。
matrix[2][2]:所在行和所在列都没有标记,保持 1。

最终结果:

text 复制代码
[
  [1, 0, 1],
  [0, 0, 0],
  [1, 0, 1]
]

6. Java 代码完整注释

java 复制代码
class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;

        // rowZero[i] 为 true,表示第 i 行最终需要全部置为 0。
        boolean[] rowZero = new boolean[m];

        // colZero[j] 为 true,表示第 j 列最终需要全部置为 0。
        boolean[] colZero = new boolean[n];

        // 第一阶段:只记录原矩阵中哪些行、列出现过 0。
        // 此阶段不修改 matrix,避免新写入的 0 干扰后续判断。
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == 0) {
                    rowZero[i] = true;
                    colZero[j] = true;
                }
            }
        }

        // 第二阶段:根据第一阶段的行、列标记统一置 0。
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                // 只要当前元素所在行或所在列原本存在 0,
                // 当前元素就需要置为 0。
                if (rowZero[i] || colZero[j]) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

7. 为什么这版时间是 O(m * n)

矩阵有:

text 复制代码
m 行,n 列

第一阶段要扫描每个元素一次:

text 复制代码
O(m * n)

第二阶段也要扫描每个元素一次:

text 复制代码
O(m * n)

总时间:

text 复制代码
O(m * n) + O(m * n)
= O(2 * m * n)
= O(m * n)

大 O 忽略常数 2

8. 为什么额外空间是 O(m + n)

额外创建了:

text 复制代码
rowZero:长度为 m。
colZero:长度为 n。

因此额外空间是:

text 复制代码
O(m + n)

它不满足题目进阶要求的常数级额外空间,但这是最直观、最适合先理解的解法。

9. 原地版本只是后续优化

题目的进阶原地版本,会把:

text 复制代码
rowZero 和 colZero

压缩进矩阵的第一列和第一行中,并额外用两个布尔变量保存第一行、第一列原本是否有 0

它的本质没有变,仍然是:

text 复制代码
先标记,再修改。

变化只是:

text 复制代码
原来用两个额外数组标记。
后来改为复用矩阵第一行、第一列标记。

因此先掌握本篇标记数组版本即可。理解"原地版本"前,首先要把"两阶段处理、防止 0 扩散"这个核心逻辑稳定下来。

10. 总结

这题属于:

text 复制代码
矩阵 / 标记数组 / 两阶段处理

最核心的原则是:

text 复制代码
不能边扫描边直接清零。
必须先记录原始 0 影响哪些行、哪些列,再统一修改。

用两个数组表达就是:

text 复制代码
rowZero[i] 记录第 i 行是否需要清零。
colZero[j] 记录第 j 列是否需要清零。

最后对于每个位置:

text 复制代码
rowZero[i] || colZero[j] 为 true,就将 matrix[i][j] 置为 0。

可以把整题记成一句话:

text 复制代码
先标记要清零的行和列,再统一清零,避免新写入的 0 继续扩散。
相关推荐
栋***t1 小时前
从“纸质试卷”到“AI智能组卷”,麦塔在线考试系统如何重构出题逻辑?
java·大数据·人工智能·算法·重构
wabs6661 小时前
关于图论【卡码网100.最大岛屿的面积的思考】
数据结构·算法·图论
CHANG_THE_WORLD1 小时前
深入理解递归:从函数调用到调用栈的完整执行过程
java·开发语言·算法
geovindu3 小时前
go:Backtracking Algorithm
开发语言·后端·算法·golang·回溯算法
微露清风3 小时前
模拟算法学习记录
学习·算法
KaMeidebaby3 小时前
卡梅德生物技术快报 | abcore 纳米抗体文库:从PNAS论文看纳米抗体理性设计:构象熵作为亲和力预测新指标的技术实现
java·开发语言·人工智能·算法·机器学习
问商十三载4 小时前
2026法律行业AI引擎生成式优化怎么优化?三层专业加固提排名,零成本提33%引用率附适配表
java·前端·人工智能·算法
zander2584 小时前
138. 随机链表的复制
数据结构·算法·链表