程序员面试金典:面试题 01.07. 旋转矩阵


给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。
不占用额外内存空间能否做到?

//使用了额外内存空间
class Solution {
    public void rotate(int[][] matrix) {
        int m = matrix.length;
        int[][] copyMatrix = new int[m][m];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < m; j++) {
                copyMatrix[i][j] = matrix[m - 1 - j][i];
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < m; j++) {
                matrix[i][j] = copyMatrix[i][j];
            }
        }
    }
}

进阶:不使用额外空间
观察图中颜色相同的四个位置,当旋转 90 度后,对应位置的元素发生了顺时针的交换。

而相隔的两个位置是中心对称的,基于此可以计算出发生交换的四个元素 位置关系。
设四个位置中,位于 左上角区域 的位置坐标为 (i,j),则按顺时针顺序,四个位置分别为(i,j), (j, n-i-1), (n-i-1,n-j-1), (n-j-1,i)。其中 n 为 matrix.size(), i, j 分别为matrix的行列下标,从 0 开始。
整个矩阵的旋转可以理解为 起点都在左上角区域,然后依次顺时针移动。
matrix.size() 为奇数时,位置的对应关系相同,但左上角区域并 不是整个矩阵的四分之一,如下图示:

其实就是多了中间列的上半部分。

那么现在捋一下如何 原地操作元素:枚举左上区域的所有位置,然后通过上面总结的位置关系直接交换元素。
对于一个位置 (i,j),需要 交换三次:

swap(matrix, i, j, j, n - 1 - i);
swap(matrix, i, j, n - 1 - i, n - 1 - j);
swap(matrix, i, j, n - 1 - j, i);

整体代码如下:

class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        if (n == 0) {
            return;
        }
        int row = n / 2 - 1;//左上角区域最下面一行
        int column = (n - 1) / 2;//左上角区域最右面一列
        for (int i = 0; i <= row; i++) {//数学知识,两两中心对称
            for (int j = 0; j <= column; j++) {
                swap(matrix, i, j, j, n - 1 - i);
                swap(matrix, i, j, n - 1 - i, n - 1 - j);
                swap(matrix, i, j, n - 1 - j, i);
            }
        }
    }
    private void swap(int[][] matrix, int i, int j, int m, int n) {
        int temp = matrix[i][j];
        matrix[i][j] = matrix[m][n];
        matrix[m][n] = temp;
    }
}