48. 旋转图像 - 力扣(LeetCode)
一、题目要求
给定一个 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].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
以上题目来自LeetCode
一、解法1-设定边界 O(N^2) 原地旋转
这个题目与螺旋矩阵十分相似,也是可以设定边界,操作完外圈后再操作内圈。不同的是这个题目要改变矩阵的值。
传送门:每日一练:螺旋矩阵
首先,这个题目要求矩阵顺时针旋转90°,物理上就是把矩阵向右推倒,就可以得到结果,但是在逻辑上需要我们自己一个一个的改变值。幸运的是,我们只要把最外层的旋转逻辑写好,更改边界就可以适用于内层的逻辑了,我们先找一下旋转的规律:
以matrix[0][0]为参照,根据题目的例子在旋转前后对它的位置做记录:
矩阵边长 | 顺时针移动格子数 |
3 | 2 |
4 | 3 |
可以发现:移动距离=矩阵边长-1;
(1)先写移动一格的逻辑;
(2)根据边长决定移动次数;
(3)移动完一层后更新边长和边界即可;
为了方便,我是先记录边角的值,然后从后向前赋值的。
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int length_left = 0; // 左边界
int length_right = matrix[0].size() - 1; // 右边界
int width_top = 0; // 上边界
int width_below = matrix.size() - 1; // 下边界
while (length_right - length_left > 0) {
int n = length_right-length_left+1; // 边长
for (int j = 0; j < n-1; j++) {
int tmp1 = matrix[width_top][length_right];
for (int i = length_right; i > length_left; i--) {
matrix[width_top][i] = matrix[width_top][i - 1];
}
int tmp2 = matrix[width_below][length_right];
for (int i = width_below; i > width_top + 1; i--) {
matrix[i][length_right] = matrix[i - 1][length_right];
}
matrix[width_top + 1][length_right] = tmp1;
int tmp3 = matrix[width_below][length_left];
for (int i = length_left; i < length_right - 1; i++) {
matrix[width_below][i] = matrix[width_below][i + 1];
}
matrix[width_below][length_right - 1] = tmp2;
for (int i = width_top; i < width_below - 1; i++) {
matrix[i][length_left] = matrix[i + 1][length_left];
}
matrix[width_below - 1][length_left] = tmp3;
}
// 更新边界
length_left++;
length_right--;
width_top++;
width_below--;
}
}
};
内存优化:
实际上这个题目要求矩阵是个正方形,所以每次循环时 length_right 与 width_below 是一样的,统一用 rb 表示; length_left 与 width_top 也是一样的,统一用 lt 表示,优化后的代码如下:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int lt = 0; // 左边界+上边界
int rb = matrix[0].size() - 1; // 右边界+下边界
while (rb - lt > 0) {
for (int j = 0; j < rb-lt; j++) {
int tmp1 = matrix[lt][rb];
for (int i = rb; i > lt; i--) {
matrix[lt][i] = matrix[lt][i - 1];
}
int tmp2 = matrix[rb][rb];
for (int i = rb; i > lt + 1; i--) {
matrix[i][rb] = matrix[i - 1][rb];
}
matrix[lt + 1][rb] = tmp1;
int tmp3 = matrix[rb][lt];
for (int i = lt; i < rb - 1; i++) {
matrix[rb][i] = matrix[rb][i + 1];
}
matrix[rb][rb - 1] = tmp2;
for (int i = lt; i < rb - 1; i++) {
matrix[i][lt] = matrix[i + 1][lt];
}
matrix[rb - 1][lt] = tmp3;
}
// 更新边界
lt++;
rb--;
}
}
};