Problem: 48. 旋转图像
题目:给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
文章目录
整体思路
这段代码旨在解决一个经典的矩阵问题:旋转图像 (Rotate Image) 。问题要求将一个 N x N
的二维矩阵顺时针旋转 90 度 ,并且要求是原地完成,即不使用额外的矩阵空间。
该算法采用了一种非常经典且优雅的 "两步变换法" 来实现原地旋转。它将复杂的旋转操作分解为两个更简单、更直观的线性代数变换:转置 和 水平翻转。
-
第一步:沿主对角线转置矩阵
- 什么是转置 :矩阵的转置操作就是将其行和列互换。元素
matrix[i][j]
会和matrix[j][i]
交换位置。 - 实现方式 :代码通过一个嵌套循环来实现。外层循环
for (int i = 0; i < m; i++)
遍历每一行,内层循环for (int j = 0; j < i; j++)
只遍历主对角线左下方的元素。 - 为什么
j < i
:这个条件是关键,它确保了每个位于对角线一侧的元素(i, j)
只与其对应的(j, i)
交换一次。如果j
遍历到m-1
,那么每个元素会被交换两次,最终导致矩阵变回原样。 - 效果 :完成这一步后,原始矩阵
[[1,2,3],[4,5,6],[7,8,9]]
会变成[[1,4,7],[2,5,8],[3,6,9]]
。
- 什么是转置 :矩阵的转置操作就是将其行和列互换。元素
-
第二步:水平翻转矩阵的每一行
- 什么是水平翻转:对矩阵的每一行进行独立的反转操作。
- 实现方式 :代码通过一个外层
for-each
循环遍历矩阵的每一行row
。对于每一行,再通过一个内层循环for (int i = 0; i < row.length / 2; i++)
来实现该行的原地反转。这个内层循环使用经典的双指针思想(一个从头开始,一个从尾开始)来交换元素。 - 效果 :对上一步转置后的矩阵
[[1,4,7],[2,5,8],[3,6,9]]
的每一行进行翻转,会得到:[1,4,7]
->[7,4,1]
[2,5,8]
->[8,5,2]
[3,6,9]
->[9,6,3]
- 最终的矩阵就是
[[7,4,1],[8,5,2],[9,6,3]]
,这正是原始矩阵顺时针旋转 90 度的结果。
通过将旋转分解为"转置 + 翻转"这两个步骤,算法巧妙地实现了原地旋转,逻辑清晰且易于理解。
完整代码
java
class Solution {
/**
* 将一个 N x N 的二维矩阵原地顺时针旋转 90 度。
* @param matrix 要旋转的 N x N 矩阵
*/
public void rotate(int[][] matrix) {
// 获取矩阵的维度(N x N,所以 m 即为 N)
int m = matrix.length;
// 步骤 1: 沿主对角线转置矩阵
// 即 matrix[i][j] 与 matrix[j][i] 交换
for (int i = 0; i < m; i++) {
// 内层循环 j < i 是关键,确保每个元素只交换一次
for (int j = 0; j < i; j++) {
// 执行交换
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 步骤 2: 水平翻转矩阵的每一行
// 遍历矩阵的每一行
for (int[] row : matrix) {
// 使用双指针法原地反转当前行
// i 从行首开始,m - 1 - i 从行尾开始
for (int i = 0; i < row.length / 2; i++) {
// 执行交换
int temp = row[i];
row[i] = row[m - 1 - i];
row[m - 1 - i] = temp;
}
}
}
}
时空复杂度
时间复杂度:O(N^2)
- 转置操作 :
- 第一个双层
for
循环的迭代次数是1 + 2 + ... + (N-1)
,即N * (N-1) / 2
。 - 因此,这部分的时间复杂度是 O(N^2)。
- 第一个双层
- 翻转操作 :
- 第二个双层
for
循环,外层循环执行N
次(遍历每一行)。 - 内层循环对每一行执行
N/2
次交换操作。 - 总的操作次数约为
N * (N/2)
。 - 因此,这部分的时间复杂度也是 O(N^2)。
- 第二个双层
综合分析 :
算法的总时间复杂度是 O(N^2) + O(N^2) = O(N^2)。这是不可避免的,因为我们至少需要访问矩阵中的每一个元素一次。
空间复杂度:O(1)
- 主要存储开销 :该算法直接在输入的
matrix
数组上进行修改,没有创建任何新的、与输入规模N
成比例的数据结构。 - 辅助变量 :只使用了
m
,i
,j
,temp
和row
等几个常数数量的变量。
综合分析 :
算法所需的额外辅助空间是常数级别的。因此,其空间复杂度为 O(1),完全满足了原地旋转的要求。
参考灵神
建议看一下灵神题解太强了