0048.旋转图像
难度:🟡 中等
标签:数组
、数学
、矩阵
链接:48. 旋转图像
题目描述
给定一个 n × n 的二维矩阵 matrix
表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
解题思路
核心思想
本题的目标是在原地将一个 n×n 矩阵顺时针旋转 90 度。直接计算每个元素旋转后的新位置会非常复杂。一个更巧妙的核心思想是将这个复杂的旋转操作分解为两个更简单的、对称的变换:
沿主对角线翻转(转置):将矩阵的行和列进行互换。
沿垂直中线翻转(水平翻转):将矩阵的每一行进行反转。
通过依次执行这两个操作,可以完美地实现顺时针 90 度的旋转效果。
思路选择
两次翻转法 是解决此问题的标准最优思路,因为它能轻松地实现原地修改,且逻辑清晰。
第一步:主对角线翻转(转置)。我们遍历矩阵的上半部分(或下半部分),将元素
matrix[i][j]
与matrix[j][i]
进行交换。第二步:水平翻转。我们遍历矩阵的每一行,将该行内的元素进行反转。这可以通过对每一行使用双指针法来实现。
关键步骤
初始化:获取矩阵的维度
n
。转置矩阵: a. 使用双层循环,外层循环
i
从 0 到n-1
,内层循环j
从i+1
到n-1
(只遍历上三角或下三角,避免重复交换)。 b. 在循环中,交换matrix[i][j]
和matrix[j][i]
。水平翻转每一行: a. 遍历矩阵的每一行。 b. 对每一行使用双指针(
left
从头,right
从尾)向中间靠拢,交换left
和right
指向的元素,直到完成该行的反转。完成:经过这两步操作后,原矩阵
matrix
就被成功地顺时针旋转了 90 度。
代码实现
/**
* @param {number[][]} matrix
* @return {void} Do not return anything, modify matrix in-place instead.
*/
var rotate = function (matrix) {
// 变量命名稍有歧义,rows/cols 通常指维度,这里指最大索引
let rows = matrix.length - 1, cols = matrix[0].length - 1;
// 1. 沿主对角线翻转 (转置)
for (let i = 0; i <= rows; i++) {
for (let j = 0; j <= cols; j++) {
// 通过 i < j 确保只遍历上三角,避免重复交换
if (i < j) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
}
}
}
// 2. 水平翻转每一行
for (let i = 0; i <= rows; i++) {
let left = 0, right = cols;
// 手动实现行的反转
while (left <= right) {
[matrix[i][left], matrix[i][right]] = [matrix[i][right], matrix[i][left]];
left++;
right--;
}
}
};
复杂度分析
时间复杂度:O(n²) 其中 n 是矩阵的边长。我们需要遍历矩阵中的每个元素两次(一次转置,一次翻转)。
空间复杂度:O(1) 所有操作都是在原矩阵上进行的,没有使用与输入规模成正比的额外空间。
相关题目
总结
本题是矩阵原地操作的经典问题。通过将一个复杂的几何旋转操作,分解为两次简单且对称的翻转操作,可以极大地简化问题的求解思路和代码实现,是算法中“问题转换”思想的绝佳体现。