题目
给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。
不占用额外内存空间能否做到?
题目分析
- 题目中没有给出逆时针还是顺时针旋转,我们这里规定顺时针旋转
- 本题目我使用旋转交换的方法,使用一个元素大小的额外空间
- 推一下元素交换后坐标的变化,官方解题或者其他博客用的是观察法,但是观察法非常容易忘,所以就推一下:
设一个元素A的坐标是(i, j),转换为极坐标是,瞬时针旋转
,坐标变为
,展开后变成了
, 可以看做: 系数矩阵*原坐标=新坐标
当=
的时候,系数矩阵变成了
换回笛卡尔坐标系:
变换后得到的是(-j,i),由于代码中的索引和矩阵的元素位置不是同一形式,当坐标是负值的时候,变换为N-1-j,N-1-j再乘以负值就是j,所以变换的坐标为:
- (i,j) 移动到(N-1-j, i)
- (N-1-j, i) 移动到 (N-1-i,N-1-j)
- (N-1-i,N-1-j)移动到(j, N-1-i)
- (j, N-1-i)移动到(i,j)
代码实现
public void rotate(int[][] matrix) {
int n = matrix.length;
// 外层循环遍历到中间位置,奇数边长包含中间位置。
for (int i = 0; i < n / 2; i++) {
// 内层循环遍历到中间位置,奇数边长不包含中间位置。
for (int j = 0; j < (n + 1) / 2; j++) {
int tmp = martix[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;
}
}
}
代码分析
问题:为什么外层遍历的次数是n/2,内层的遍历次数(n+1)/2?
外层和内层的遍历次数可以互换,矩阵的元素旋转只需要考虑四 分之一,但是当边长N等于奇数的时候,无法均匀分成四部分,有一部分元素在边线上,边线的元素只能有一个边属于该部分。当n是偶数的时候,n/2和(n+1)/2相等,当n是奇数的时候,(n+1)/2比n/2大1,就是这四分之一部分包括一条边线,不包括另一条。