给定一个 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 == matrix.length == matrix[i].length1 <= n <= 20-1000 <= matrix[i][j] <= 1000
思路,我本来是想在外层套个循环,四个四个替换,由外到内,但是其实对角翻转这个思路其实更简单一些。
1. 算法核心思想:巧妙的“几何魔法”
这道题最严苛的要求是“必须在原地(in-place)旋转”,意味着绝对不允许去申请一个一模一样大的新二维数组来做中转。
为了完美实现原地修改,利用了几何空间规律,将一个复杂的“顺时针旋转 90 度”动作,拆解成了两个极其简单的镜面翻转动作: 顺时针旋转 90 度 = 先沿主对角线翻转 + 再沿垂直中轴线翻转(按行反转)。
2. 逻辑拆解
-
第一步:主对角线翻转(矩阵转置)
- 目标:以左上角到右下角的对角线为轴,将矩阵对折。这在数学上叫做“矩阵转置”,即把
matrix[i][j]和matrix[j][i]互换位置。
- 目标:以左上角到右下角的对角线为轴,将矩阵对折。这在数学上叫做“矩阵转置”,即把
-
第二步:逐行水平反转
- 目标:转置完之后,原来矩阵最上面的一行,变成了最左边的一列。但顺时针旋转 90 度后,它本应该在最右边。
- 执行: C++ 标准库的
reverse()。通过一个极其简单的for循环,遍历每一行,把每一行的元素像烤肉一样直接“左右翻面”。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
//对角线翻转,每一行再翻转
for (int i = 0; i < matrix.size() - 1; i++) {
for (int j = i + 1; j < matrix[0].size(); j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
for (int i = 0; i < matrix.size(); i++) {
reverse(matrix[i].begin(), matrix[i].end());
}
}
};
3. 复杂度剖析
- 时间复杂度:O**(N2)**。其中 N 是矩阵的边长。第一步对角线交换操作了大约一半的元素,第二步反转操作了全部元素。总体操作次数依然严格与矩阵的总面积(元素总个数)成正比,属于最优的时间下限。
- 空间复杂度:O**(1)**。这也是这套解法最值钱的地方。整个手术全过程都在原矩阵上完成,仅仅用了一个
temp整型变量做交换中转,内存消耗被压榨到了理论极限。
