💻 [LeetCode Hot100] 矩阵置零|原地标记,Java实现!图解+代码,小白也能秒懂!
✏️本文对应题目链接:矩阵置零
📌 题目描述
给定一个 m x n
的矩阵,如果一个元素为 0
,则将其所在行和列的所有元素都设为 0
。请使用原地算法。
示例:
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
解释:将第二行和第二列全部置零。
🧠 解题思路(图文分解)
❗ 核心难点
如何在O(1)空间复杂度内完成矩阵置零?
方法一:原地标记(黄金思路)✨
关键步骤:
- 标记首行和首列:
- 使用首行和首列作为标记位,记录是否需要置零
- 单独标记首行和首列是否需要置零
- 遍历矩阵:
- 如果
matrix[i][j] == 0
,则将matrix[i][0]
和matrix[0][j]
置零
- 如果
- 根据标记置零:
- 遍历首行和首列,将对应的行和列置零
- 处理首行和首列是否需要置零
图解原地标记
输入矩阵:
matrix = [
[1, 1, 1],
[1, 0, 1],
[1, 1, 1]
]
步骤1:标记首行和首列
首行是否需要置零:false
首列是否需要置零:false
步骤2:遍历矩阵
i=1, j=1: matrix[1][1]=0 → 标记matrix[1][0]=0, matrix[0][1]=0
步骤3:根据标记置零
- 根据matrix[1][0]=0,将第二行置零 → [1,0,1]
- 根据matrix[0][1]=0,将第二列置零 → [1,0,1]
- 最终矩阵:
[
[1, 0, 1],
[0, 0, 0],
[1, 0, 1]
]
🚀 代码实现
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
boolean firstRowZero = false; // 首行是否需要置零
boolean firstColZero = false; // 首列是否需要置零
// 标记首行和首列是否需要置零
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) {
firstColZero = true;
break;
}
}
for (int j = 0; j < n; j++) {
if (matrix[0][j] == 0) {
firstRowZero = true;
break;
}
}
// 遍历矩阵,标记需要置零的行和列
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;
}
}
}
// 根据标记置零
for (int i = 1; i < m; i++) {
if (matrix[i][0] == 0) {
for (int j = 1; j < n; j++) {
matrix[i][j] = 0;
}
}
}
for (int j = 1; j < n; j++) {
if (matrix[0][j] == 0) {
for (int i = 1; i < m; i++) {
matrix[i][j] = 0;
}
}
}
// 处理首行和首列
if (firstRowZero) {
for (int j = 0; j < n; j++) {
matrix[0][j] = 0;
}
}
if (firstColZero) {
for (int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
}
}
💡 复杂度分析
- 时间复杂度:O(m * n) → 遍历矩阵两次
- 空间复杂度:O(1) → 仅用常数空间
方法二:布尔数组标记(优化思路)
关键思路:使用两个布尔数组分别记录需要置零的行和列。
class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length;
boolean[] rowZero = new boolean[m]; // 记录需要置零的行
boolean[] colZero = new boolean[n]; // 记录需要置零的列
// 标记需要置零的行和列
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;
}
}
}
// 根据标记置零
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (rowZero[i] || colZero[j]) {
matrix[i][j] = 0;
}
}
}
}
}
🌟 总结要点
✅ 原地标记核心思想:利用首行和首列作为标记位,节省空间
✅ 布尔数组优化:空间复杂度O(m + n),适合小规模矩阵
✅ 适用场景:矩阵操作、稀疏矩阵处理