LeetCode48.旋转图像/面试题.01.07 旋转矩阵
Question
给你一幅由
N × N
矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。不占用额外内存空间能否做到?
Example
Example 1:
给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
Example 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]
]
Idea
Solution1:辅助数组
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
// C++ 拷贝初始化
auto matrix_new = matrix;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix_new[j][n - i - 1] = matrix[i][j];
}
}
// vectoc运算符重载
matrix = matrix_new;
}
};
Solution2:翻转+对角线互换
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
//原地算法1
for(int i = 0; i < matrix.size() >> 1; i++){
for(int j = 0; j < matrix.size(); j++){
swap(matrix[i][j],matrix[matrix.size()-i-1][j]);
}
}
//对角线互换,主对角线不需要动
for(int i = 0; i < matrix.size() -1; i++){
for(int j = i + 1; j < matrix.size(); j++){
swap(matrix[i][j],matrix[j][i]);
}
}
}
};
Solution3:跑火车改进版
思路:
- 首先观察矩阵可以发现:
- 原矩阵和目标矩阵的差异规律
- 4x4矩阵
- 4x4矩阵外圈顺时针移动3步
- 4x4矩阵外圈顺时针移动1步
- 3x3矩阵
- 3x3矩阵外圈顺时针移动2步
- 3x3矩阵外圈顺时针移动0步(不动)
下面以4x4矩阵举例
5 | 1 | 9 | 11 |
---|---|---|---|
2 | 4 | 8 | 10 |
13 | 3 | 6 | 7 |
15 | 14 | 12 | 16 |
外圈顺时针移动1步
2 | 5 | 1 | 9 |
---|---|---|---|
13 | 4 | 8 | 11 |
15 | 3 | 6 | 10 |
14 | 12 | 16 | 7 |
外圈顺时针移动2步
13 | 2 | 5 | 1 |
---|---|---|---|
15 | 4 | 8 | 9 |
14 | 3 | 6 | 11 |
12 | 16 | 7 | 10 |
外圈顺时针移动3步
15 | 13 | 2 | 5 |
---|---|---|---|
14 | 4 | 8 | 1 |
12 | 3 | 6 | 9 |
16 | 7 | 10 | 11 |
内圈顺时针移动1步
15 | 13 | 2 | 5 |
---|---|---|---|
14 | 3 | 4 | 1 |
12 | 6 | 8 | 9 |
16 | 7 | 10 | 11 |
3x3类似,此处不再举例,分析上面表格可以发现可以优化空间,上面移动步骤没有实现一步到位,如何实现一步到位呢?
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 |
我们可以根据上面表格一中元素(5,11,16,15), (1,10,12,13), (9,7,14,2)分组,做顺时针移动,每次移动3位,实现一步到位,注意需要申请tmp存储最后一个被覆盖的地方,代码中存放的是matrix[i][j]处的元素,内圈同理,移动1位,可以对照代码理解其中处理细节
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
//原地算法2
int n = matrix.size();
//scope是每次需要移动多少位
for(int i = 0,scope = n - 1; i < matrix.size() >> 1 && scope > 0; i++,scope-=2){
for(int j = i; j < i + scope; j++){
int tmp = 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] = tmp;
}
}
}
};