一,问题描述
今天碰到一个简单的面试题,矩阵旋转。给定一个n*n的矩阵,要求逆时针旋转90度,要求两个角要同时旋转。只能使用O(1)的辅助空间。 例如,一个4*4的矩阵,旋转前后图1所示。
图1 4*4的矩阵,旋转前后对比图。
二,解决思路
这个问题,关键就是坐标之间的转换关系,其实弄明白这个就很简单了。
1, 确定关系
为了想明白坐标的转换关系,先来看一个特例,看看四个角上的数字都转到哪了。
对应的四个坐标及转换关系为:
用语言唐僧般的描述一下: 第一行的第一列,换到最后一行的第一列; 最后一行的第一列,换到最后一行的最后一列;....类似
再来看看另外一个例子,旋转第一行第二列有关的数:
根据这两个例子,确定下旋转的坐标规律,其实也是符合认知的(抽象思维好,可以直接想到)
a[0][1] <--> a[n-1-1][0], a[n-2][0] <--> a[n-1-0][n-2] ,a[n-1][n-1-1] <--> a[1][n-1], a[1][n-1-0]<-->a[0][1]
前一个数的行,是后一个数的列。 第一个数的列和第二个数的行是n-1的关系。注意最后一个 n-1-(n-1-j) = j
当然,这些数之间的距离不一定是这样,也有可能是刚好相邻的四个数。
2,确定范围
确定了关系之后,就要确定i和j的范围,根据这四个坐标的范围就可以确定i和j的范围了。
比如根据a[i][j]和a[n-1-i] [n-1-j] , 0=<i < n-1-i ; 0=<j <=n-j -1; 其实就是旋转左上角。
当然你也可以选另外两个来确定范围,旋转右上角啊,等等。
三,代码
public class RotateMatrix {
public static void rotateMatrix(int[][] matrix) {
int n = matrix.length;
int i = 0, j = 0;
for (i = 0; i < n-1-i; i++) {
for (j = 0; j <= n-1-j; j++) {
//请参考上图理解
System.out.println(i + " " + j);
int tmp = matrix[n-1-j][i];
matrix[n-1-j][i] = matrix[i][j];
matrix[i][j] = matrix[j][n-1-i];
matrix[j][n-1-i] = matrix[n-1-i][n-1-j];
matrix[n-1-i][n-1-j] = tmp;
}
}
}
public static void display(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a.length; j++)
System.out.print(a[i][j] + "\t");
System.out.println();
}
}
public static int[][] generateMatrix(int n) {
int c = 1;
int[][] a = new int[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
a[i][j] = c++;
return a;
}
public static void main(String[] args) {
int[][] matrix = generateMatrix(6);
display(matrix);
System.out.println("After rotation: ");
rotateMatrix(matrix);
display(matrix);
}
}
四,跑的一些例子
n = 7
五,扩展
对于任意的n*m的矩阵,如果要逆时针旋转,转换的思路也是类似。只要把上述的坐标关系和坐标范围中的n适当地换成m就行了。这个应该好理解吧。