题目描述:
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
输入: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]]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-image
Intuition:
我们可以观察旋转前后的矩阵得到结论,原矩阵中位于第 i 行,第 j 列的数, 在旋转之后,将移位到第 j 行,倒数第i 列的位置上去。
max[row][col] = max[col][n - 1 - row]
具体实现
两种方法。第一种为循环流动。第二种为翻转
方法一:
逐“圈”进行循环,以题目描述中的示例为例
蓝色为第一圈,橙色为第二圈。逐圈往里收紧直到中心点。
在每一圈中,都可以分为几个组。
在第一圈中,我们先来看第一组{5,11,16,15},也就是二维矩阵的四个角。数字5移动到数字11的位置,数字11移动到数字16的位置。数字16移动到数字15的位置,数字15移动到数字5的位置,也就是说,这四个数字为一组,每一个数字都循环流动到了下一个位置。
仍然是第一圈,继续。第二组{1,10,12,13},第三组{9,17,14,2}同理流动。
第一圈完成,第二圈同理流动。
圈为外循环,组为内循环。具体实现如下。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int i , j;
int n = matrix.size();
for(i = 0; i < n / 2; i++){
for(j = i ; j < n - 1 - i ; j++){
int temp = matrix[i][j];
matrix[i][j] = matrix[n - 1 - j][i];
matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j];
matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i];
matrix[j][n - 1 - i] = temp;
}
}
}
};
循环体中,流动的具体实现与intuition有所区别的原因所在,是因为先保存下来了第一个数字,然后让每组最后一个数字先填入第一个数字所在的位置,接着倒数第二个数字填入最后一个数字所在的位置,相当于和intuition倒着来,最后将第一个数字填入第二个数字所在的位置中。原理都是相同的。
方法二:
在一维数组的循环数组题目中,我们采用了,先翻转前部数组,再翻转后部数组,最后整体翻转的策略。这个思路也可以应用到二维数组中,通过翻转来简化实现。
在本题中,采用先水平方向上下翻转,再沿着正对角线镜像的方法,来实现顺时针旋转九十度的效果。具体实现如下:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for(int i = 0; i < n / 2; i++){
swap(matrix[i], matrix[n - 1 - i]);
}
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
swap(matrix[i][j], matrix[j][i]);
}
}
}
};
事实上,
水平翻转相当于matrix[row][col] = matrix[n-1-row][col]。
沿正对角线镜像相当于matrix[n-1-row][col]=matrix[col][n-1-row]。
不难看出,两个式子结合,与Intuition仍然是相符的。