矩阵题模板(螺旋矩阵 · 搜索矩阵 · 旋转图像)
medium矩阵模拟二分查找
螺旋矩阵(LeetCode 54)
按层模拟,维护四个边界 top/bottom/left/right:
List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (int i = left; i <= right; i++) res.add(matrix[top][i]);
top++;
for (int i = top; i <= bottom; i++) res.add(matrix[i][right]);
right--;
if (top <= bottom) {
for (int i = right; i >= left; i--) res.add(matrix[bottom][i]);
bottom--;
}
if (left <= right) {
for (int i = bottom; i >= top; i--) res.add(matrix[i][left]);
left++;
}
}
return res;
}
螺旋矩阵 II(LeetCode 59):生成 n×n 螺旋矩阵,思路一样填数即可。
搜索二维矩阵(LeetCode 74)
行列均升序,整体可看成一个有序数组做二分:
boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length, n = matrix[0].length;
int lo = 0, hi = m * n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
int val = matrix[mid / n][mid % n];
if (val == target) return true;
if (val < target) lo = mid + 1;
else hi = mid - 1;
}
return false;
}
搜索二维矩阵 II(LeetCode 240):行列各自升序,但行列有交叉,从右上角开始排除:
boolean searchMatrixII(int[][] matrix, int target) {
int r = 0, c = matrix[0].length - 1;
while (r < matrix.length && c >= 0) {
if (matrix[r][c] == target) return true;
if (matrix[r][c] > target) c--; // 当前列全部偏大,左移
else r++; // 当前行全部偏小,下移
}
return false;
}
时间:O(m+n)。
旋转图像(LeetCode 48)
原地旋转 90 度:先沿主对角线转置,再水平镜像。
void rotate(int[][] matrix) {
int n = matrix.length;
// 1. 转置(对角线互换)
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) {
int t = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = t;
}
// 2. 每行左右翻转
for (int i = 0; i < n; i++) {
int lo = 0, hi = n - 1;
while (lo < hi) {
int t = matrix[i][lo];
matrix[i][lo++] = matrix[i][hi];
matrix[i][hi--] = t;
}
}
}
矩阵置零(LeetCode 73)
用第一行/列作标记,避免额外 O(mn) 空间:
void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean firstRowZero = false, firstColZero = false;
// 记录第一行/列是否含0
for (int j = 0; j < n; j++) if (matrix[0][j] == 0) firstRowZero = true;
for (int i = 0; i < m; i++) if (matrix[i][0] == 0) firstColZero = true;
// 用第一行/列记录标记
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++)
for (int j = 1; j < n; j++)
if (matrix[i][0] == 0 || matrix[0][j] == 0) matrix[i][j] = 0;
if (firstRowZero) Arrays.fill(matrix[0], 0);
if (firstColZero) for (int i = 0; i < m; i++) matrix[i][0] = 0;
}
空间 O(1),时间 O(mn)。