**摘要:**本文解析 LeetCode 热题 100 中矩阵部分的题目。


矩阵
73 矩阵置零

核心逻辑: 通过两个布尔数组分别记录需要置零的行和列,先遍历矩阵标记所有含 0 的行和列,再根据标记结果分别对行、列批量置零,最终实现原地修改矩阵的目标(核心是 "标记 - 置零" 的分步逻辑)。
关键步骤:
-
初始化标记数组:创建两个布尔数组
rowZero(长度为矩阵行数 m)和colZero(长度为矩阵列数 n),分别用于记录哪些行 / 列需要置零,初始值均为 false。 -
遍历标记行 / 列:逐行逐列遍历整个矩阵,若遇到元素
matrix[i][j] = 0,则将rowZero[i]设为 true(标记第 i 行需置零)、colZero[j]设为 true(标记第 j 列需置零)。 -
置零标记行:遍历
rowZero数组,若rowZero[i] = true,则将矩阵第 i 行的所有元素置为 0。 -
置零标记列:遍历
colZero数组,若colZero[j] = true,则将矩阵第 j 列的所有元素置为 0。
java
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++) {
if (rowZero[i]) {
for (int j = 0; j < n; j++) {
matrix[i][j] = 0;
}
}
}
// 第三步:置零标记的列
for (int j = 0; j < n; j++) {
if (colZero[j]) {
for (int i = 0; i < m; i++) {
matrix[i][j] = 0;
}
}
}
}
}
54 螺旋矩阵

核心逻辑: 通过边界收缩法控制螺旋的方向和范围 ------ 定义上、下、左、右四个边界,++按 "右→下→左→上" 的顺序循环遍历矩阵元素,每完成一个方向就收缩对应边界++,直到所有元素遍历完毕并收集到结果列表中。
关键步骤:
++初始化边界与结果++:
-
定义 top = 0、bottom = 矩阵行数 - 1、left = 0、right = 矩阵列数 - 1;
-
初始化空的结果列表 res(用于存储遍历后的元素)。
++循环遍历(边界收缩)++:
-
向右遍历:遍历 [left, right] 列,收集 top 行的所有元素到 res,完成后 top++(上边界下移);
-
向下遍历:遍历 [top, bottom] 行,收集 right 列的所有元素到 res,完成后 right--(右边界左移);
-
向左遍历(需判断上下边界是否交叉):若 top ≤ bottom,遍历 [right, left] 列,收集 bottom 行的所有元素到 res,完成后 bottom--(下边界上移);
-
向上遍历(需判断左右边界是否交叉):若 left ≤ right,遍历 [bottom, top] 行,收集 left 列的所有元素到 res,完成后 left++(左边界右移);
终止条件:当 top > bottom 或 left > right 时,所有元素遍历完毕,返回结果列表 res。
java
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
if (matrix == null || matrix.length == 0) return res;
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
// 向右遍历
for (int j = left; j <= right; j++) {
res.add(matrix[top][j]);
}
top++;
// 向下遍历
for (int i = top; i <= bottom; i++) {
res.add(matrix[i][right]);
}
right--;
// 向左遍历(判断边界)
if (top <= bottom) {
for (int j = right; j >= left; j--) {
res.add(matrix[bottom][j]);
}
bottom--;
}
// 向上遍历(判断边界)
if (left <= right) {
for (int i = bottom; i >= top; i--) {
res.add(matrix[i][left]);
}
left++;
}
}
return res;
}
}
48 旋转图像

**核心逻辑:**通过 "矩阵转置 + 每行左右翻转" 两步操作实现原地顺时针旋转 90 度 ------ 先将矩阵行和列互换完成转置,再对转置后的每一行进行左右翻转,无需额外矩阵空间,仅通过元素交换完成原地修改。
关键步骤:
-
转置矩阵:遍历矩阵上三角区域 (i 从 0 到 n-1,j 从 i 到 n-1),交换
matrix[i][j]和matrix[j][i],完成后矩阵行和列互换; -
翻转每行:遍历矩阵每一行(i 从 0 到 n-1),对当前行遍历前半部分列(j 从 0 到 n/2-1),交换
matrix[i][j]和matrix[i][n-1-j],完成后该行元素左右翻转。
java
public class RotateImage {
public void rotate(int[][] matrix) {
int n = matrix.length;
// 第一步:转置矩阵
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// 交换 matrix[i][j] 和 matrix[j][i]
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 第二步:对称交换
for (int i = 0; i < n; i++) {
for (int j = 0; j < n / 2; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[i][n - 1 - j];
matrix[i][n - 1 - j] = temp;
}
}
}
}
240 搜索二维矩阵 Ⅱ

**核心逻辑:**通过 "边界收缩法" 从矩阵右上角起始搜索 ------ 利用矩阵 "每行升序、每列升序" 的特性,以右上角为起始点,每次比较可排除一行或一列,逐步收缩搜索边界,无需额外空间且时间复杂度最优,高效判断。
关键步骤:
-
边界初始化:处理空矩阵边界情况(矩阵为 null / 行数为 0 / 列数为 0 时直接返回 false);定义行数 m = 矩阵长度、列数 n = 矩阵首行长度,初始化搜索起始点为矩阵右上角(row=0,col=n-1);
-
边界收缩搜索:循环判断 row <m 且 col>= 0(未越界),取当前位置值 current=matrix [row][col]:
-
若 current == target:找到目标值,直接返回 true;
-
若 current > target:当前列所有元素均大于目标值,左移列边界(col--)排除当前列;
-
若 current < target:当前行所有元素均小于目标值,下移行边界(row++)排除当前行;
-
-
终止返回:当循环因边界越界终止时,说明未找到目标值,返回 false。
java
public class SearchMatrixII {
public boolean searchMatrix(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {return false;}
int m = matrix.length;
int n = matrix[0].length;
int row = 0;
int col = n - 1;
while (row < m && col >= 0) {
int current = matrix[row][col];
if (current == target) {
return true;
} else if (current > target) {
col--;
} else {
row++;
}
}
return false;
}
}
恭喜你学习完成!✿