旋转图像
思路:
第一意识是找一个数学规律,一个公式可以找到对应的位置。
唉 想不出 没啥思路 看题解了。
一看就懂了 规律就是。。。。。。:原来第 i 行第 j 列的元素 在旋转后 会在第 j 行倒数第i列。
这种题目做少了,多做几个矩阵的总结一下规律就懂了。
法一:这是利用辅助矩阵的方法。
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++)
{//翻转后矩阵的[i][j]是之前的[n-1-j][i]
matrix_new[i][j]=matrix[n-1-j][i];
}
}
matrix=matrix_new;//再来一次值拷贝
}
};
法二:不使用辅助数组,原地进行操作,故需要考虑覆盖问题。
为什么要这么想呢,可以从n=2,3看看,可以发现旋转都是很有规律的!!!
法二是利用一个关键公式进行推导:
matrix_new[j][n - i - 1] = matrix[i][j];
这个公式的意思是,原来[i][j]位置的元素 要旋转到[j][n-i-1]。
这个时候[j][n-i-1]就要被覆盖了,我们继续看看这个位置的值旋转后要去哪。
继续代入关键公式,即令i=j,j=n-i-1 我们可以得到[j][n-i-1] 要旋转到[n-i-1][n-j-1]的位置、
我们继续看[n-i-1][n-j-1]要旋转到哪里: 令i=n-i-1,j=n-j-1,我们可以得到[n-i-1][n-j-1]要旋转到
[n-j-1][i]的位置。继续看 ,同理,[n-j-1][i]要旋转到[i][j]
可以大声喊我艹了。我们惊奇的发现闭环了,也就是[i][j]旋转到[j][n-i-1],[j][n-i-1]旋转到[n-i-1][n-j-1],[n-i-1][n-j-1]旋转到[n-j-1][i],[n-j-1][i]又旋转到[i][j],形成了闭环!!
这个时候,我们每次遍历处理四个元素就可以了,处理这四个元素的时候,存一下[i][j],即temp=[i][j],就可以对后续都进行原地赋值操作。即以下五行代码:
temp=[i][j];
[i][j]=[n-j-1][i];
[n-j-1][i]=[n-i-1][n-j-1];
[n-i-1][n-j-1]=[j][n-i-1];
[j][n-i-1]=temp;
每一次处理四个元素,总共有n*n个元素。
然后剩下的问题是如何确定遍历的范围:
- 因为每次遍历都是操作4个点,显然我们只需遍历n*n/4个格子即可.
- 直觉上n*n/4可以等于 (n/2) * (n/2) (即0 <= i < n/2 ,0 <= j < (n/2)),
- 但也可以等于n * (n/4),究竟是哪种呢?
- 可以自己模拟一下n=2 n=3就明白了。肯定是前者。
- n为偶数的时候是四等分:
- n为奇数时:
- 综上,不管n是奇数还是偶数,遍历的范围都可以表示为0 <= i < n/2 ,0 <= j < ( n+1 /2)
代码:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n=matrix.size();
for(int i=0;i<n/2;i++)
{
for(int j=0;j<(n+1)/2;j++)
{
int temp=matrix[i][j];
matrix[i][j]=matrix[n-j-1][i];
matrix[n-j-1][i]=matrix[n-i-1][n-j-1];
matrix[n-i-1][n-j-1]=matrix[j][n-i-1];
matrix[j][n-i-1]=temp;
}
}
}
};
法三:一些巧妙的方法:用翻转代替旋转
用两次翻转代替旋转:
为什么呢?
我们也分别列出沿水平翻转和沿主对角线翻转的公式:
沿水平翻转:matrix_new[n-i-1][j]=matrix[i][j]
沿对角线翻转:matrix_new[j][i]=matrix[i][j]
这两个联立,可以得到。可以得到matrix_new[j][n-i-1]=matrix[i][j] 而这个就是之前说到的关键公式。所以两次翻转就等于将图像顺时针旋转 90 度。
而这种翻转,直接用swap就好了。
代码:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n=matrix.size();
for(int i=0;i<n/2;i++)//水平翻转
{
for(int j=0;j<n;j++)
{
swap(matrix[i][j],matrix[n-i-1][j]);
}
}
for(int i=0;i<n;i++)//对角线翻转
{
for(int j=0;j<i;j++)
{
swap(matrix[i][j],matrix[j][i]);
}
}
}
};