
官方原始解法(容易想到)
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean[] row = new boolean[m];
boolean[] col = new boolean[n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/set-matrix-zeroes/solutions/669901/ju-zhen-zhi-ling-by-leetcode-solution-9ll7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
为了在不使用额外空间的情况下解决问题,我们可以利用矩阵的第一行和第一列作为标记,来记录哪些行和列需要被置零。同时,使用两个额外的布尔变量来记录第一行和第一列本身是否需要置零。
步骤分解
-
预处理标记
- 遍历矩阵,检查第一行和第一列是否存在 0,并用
row0和col0两个布尔变量记录下来。 - 再次遍历矩阵(从第二行第二列开始),如果发现
matrix[i][j] == 0,则将matrix[i][0](标记第 i 行)和matrix[0][j](标记第 j 列)置为 0。
- 遍历矩阵,检查第一行和第一列是否存在 0,并用
-
置零操作
- 遍历矩阵(从第二行第二列开始),如果
matrix[i][0]或matrix[0][j]为 0,则将matrix[i][j]置为 0。 - 根据预处理的
row0和col0标记,最后决定是否将第一行和第一列整体置零。
- 遍历矩阵(从第二行第二列开始),如果
画的丑请见谅

Java 代码实现
public void setZeroes(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
boolean row0 = false; // 标记第一行是否有0
boolean col0 = false; // 标记第一列是否有0
// 1. 检查第一行和第一列
for (int j = 0; j < n; j++) {
if (matrix[0][j] == 0) {
row0 = true;
break;
}
}
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) {
col0 = true;
break;
}
}
// 2. 用第一行和第一列标记需要置零的行和列
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
// 3. 根据标记置零(除第一行第一列外)
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0) {
matrix[i][j] = 0;
}
}
}
// 4. 最后处理第一行和第一列
if (row0) {
for (int j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
if (col0) {
for (int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
}

复杂度分析
- 时间复杂度:O (mn),我们对矩阵进行了多次线性遍历。
- 空间复杂度:O (1),我们只使用了常数级别的额外空间,符合题目 "原地算法" 的要求。
这个算法的核心作用,是在不额外占用大量内存的前提下,高效地对矩阵进行 "置零" 操作,它的价值主要体现在以下几个方面:
实际作用
1. 核心作用:原地修改,节省空间
- 空间效率:它通过复用矩阵的第一行和第一列作为 "标记位",将空间复杂度从 O (mn) 或 O (m+n) 优化到了 O (1),只使用了两个布尔变量。
- 原地修改:直接在输入矩阵上进行修改,避免了创建一个同样大小的新矩阵,这在处理大规模数据(如高清图像、传感器矩阵、大型表格)时至关重要。
2. 典型应用场景
图像处理与计算机视觉 🖼️
- 图像降噪 / 二值化:在处理图像矩阵时,经常需要将满足特定条件(如亮度低于阈值)的像素所在行 / 列置零。这个算法可以高效地完成这类任务,同时保持内存占用极低。
- 特征提取:在边缘检测或特征点提取后,需要将无关的背景区域(行 / 列)清零,以突出主体。
数据清洗与预处理 📊
- 缺失值处理:在数据分析中,矩阵中的 0 可以代表缺失值。这个算法可以快速地将包含缺失值的行和列标记并清除,为后续的机器学习模型准备干净的数据。
- 稀疏矩阵优化:在处理稀疏矩阵时,可以通过此算法快速清理掉全零行 / 列,减少存储和计算开销。
游戏与图形学 🎮
- 碰撞检测:在游戏开发中,矩阵可以表示游戏世界的网格。当检测到碰撞(某个元素为 0)时,需要将其所在的行和列(如障碍物)置零,以更新游戏状态。
- 渲染优化:在 3D 渲染中,通过置零不可见的行 / 列来优化渲染管线,减少不必要的计算。
传感器与物联网 📡
- 传感器数据过滤:在物联网设备中,矩阵可以存储来自多个传感器的时间序列数据。当某个传感器(行)或某个时间点(列)的数据异常(为 0)时,需要将其置零,以避免影响整体分析。
3. 设计思想的复用价值
这个算法体现的 "用已有空间做标记,避免额外开销" 的思想,在很多领域都有借鉴意义:
- 内存受限系统:如嵌入式设备、移动应用,内存资源非常宝贵,任何能节省空间的技巧都至关重要。
- 大数据处理:在分布式计算框架中,减少数据的复制和传输是提升性能的关键。
