这是一道难度为中等的题目,让我们来看看题目描述:
给定一个 n × n 的二维矩阵
matrix
表示一个图像。请你将图像顺时针旋转 90 度。你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
提示:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
题解
class Solution {public void rotate(int[][] matrix) {int n = matrix.length; // 获取矩阵的维度 n// **第一步:沿主对角线(左上到右下)翻转矩阵**// 交换 matrix[i][j] 和 matrix[j][i],即 matrix[i][j] 变为 matrix[j][i]for(int i = 0; i < n; i++){ // 遍历每一行for(int j = i; j < n; j++){ // 遍历当前行及其右侧部分,确保不重复交换int temp = matrix[i][j]; // 暂存 matrix[i][j] 的值matrix[i][j] = matrix[j][i]; // 交换两个对称位置的值matrix[j][i] = temp; // 赋值完成}}// **第二步:水平翻转每一行**// 将每一行的元素进行反转,使得第一列变为最后一列,实现顺时针旋转for(int[] row : matrix){reverse(row); // 调用 reverse 方法翻转当前行}}// **辅助方法:翻转一维数组**// 作用:将传入的数组左右翻转,即第一个元素与最后一个元素交换,第二个与倒数第二个交换,以此类推void reverse(int[] arr){int i = 0; // 左指针int j = arr.length - 1; // 右指针// 交换数组的左右对称元素while(i < j){int temp = arr[i]; // 暂存左侧元素arr[i++] = arr[j]; // 右侧元素赋值给左侧,同时左指针右移arr[j--] = temp; // 左侧元素赋值给右侧,同时右指针左移}}
}
题解思路解析
-
沿主对角线翻转
- 交换
(i, j)
和(j, i)
位置的元素,将行变为列,实现 转置。 - 示例:
- 交换
1 2 3 1 4 74 5 6 -> 2 5 87 8 9 3 6 9
-
水平翻转每一行
-
将每一行的元素从左到右翻转,完成最终的旋转操作。
-
示例:
-
1 4 7 7 4 12 5 8 -> 8 5 23 6 9 9 6 3
最终结果是顺时针旋转 90 度 的矩阵。
这样就完成了 原地旋转,无需额外空间,时间复杂度 O(n²),空间复杂度 O(1)。
注意在这份代码中,我们可以看到交换数组对应元素这段
// 交换数组的左右对称元素while(i < j){int temp = arr[i]; // 暂存左侧元素arr[i++] = arr[j]; // 右侧元素赋值给左侧,同时左指针右移arr[j--] = temp; // 左侧元素赋值给右侧,同时右指针左移}
是之前一道题目复用的,用两个指针实现元素的交换,代码很简洁,链接见这里:189. 轮转数组
问题与解答
[NOTE] 问题1:
//沿对角线反转二维矩阵for(int i = 0; i < n; i++){for(int j = i; j < n; j++){int temp = matrix[i][j];matrix[i][j] = matrix[j][i];matrix[j][i] = temp;}}
这里的
int j = i;
为什么这样写?因为要翻转右上方的对角吗?
解答:
是的,int j = i;
的目的是只遍历右上三角区域,从而沿主对角线(左上到右下)进行翻转,避免重复交换。
详细解析
- 主对角线的概念
以主对角线(
matrix[i][i]
,即(0,0) → (1,1) → (2,2) → …
)为对称轴。交换 对角线两侧的元素,即
matrix[i][j]
↔matrix[j][i]
。
为什么
j = i
?
j = i
确保只交换主对角线右上部分的元素,避免重复交换。如果
j
从0
开始,会导致元素被交换两次,最终不变。