旋转图像

105 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情一、题目

leetcode 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

示例 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]]

提示:

n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000

二、题解

方法一

通过观察例子的旋转结果,我们可以发现二维矩阵旋转 90 度之后的结果其实就是原矩阵的第一行元素放到旋转后矩阵的倒数第一列,第二行元素放到旋转后矩阵的倒数第二列,依次类推原矩阵的最后一行元素就是旋转后矩阵的第一列元素。所以简单的可以新建一个同等大小的数组,然后将原数组按照翻转后的顺序依次读取元素,并且按顺序存储到新数组上,然后再将新数组元素更新覆盖到原数组上。

方法二

方法一需要额外新建同等大小的数组,消耗了额外的空间并且没有在原地进行旋转操作。所以需要考虑原地修改的方法,通过观察原矩阵和旋转后的矩阵中每一个元素前后位置变化的规律.对于示例2的矩阵首先是矩阵的[0][0]位置元素旋转后是将[3][0]位置的元素替换过来,然后第[3][0]位置的元素旋转后是将[3][3]位置的元素替换过来,那么[3][3]位置的元素旋转之后是将[0][3]位置的元素替换过来,而[0][3]位置的元素是将[0][0]位置元素替换过来;那么对于[0][1]位置的元素旋转之后是将[2][0]位置的元素替换过来,[2][0]位置的元素旋转之后就是将[3][2]位置的元素替换过来,然后[3][2]位置的元素旋转之后就是将[1][3]位置的元素替换过来,[1][3]位置的元素旋转之后就是将[0][1]位置的元素替换过来。所以最终发现对于矩阵第matrix[i][j]个,i是行下标,j是列下标,n是矩阵元素长度减1(因为下标是从0开始),所以matrix[i][j] = matrix[n - j][i]matrix[n - j][i] = matrix[n - i][n - j]matrix[n - i][n - j] = matrix[j][n - i]matrix[j][n - i] = matrix[i][j],最后一步的替换因为 matrix[i][j]已经被第一步的替换了,所以需要临时变量temp记录下 matrix[i][j]的值。然后只要执行这四个元素一组的交换为总元素的一半次数即可。

方法三

最后我们还发现如果将矩阵的元素进行翻转最后也能到达旋转90°的效果,具体的可以先将矩阵的上下部分元素翻转,然后按照矩阵的左上角到右下角的一个主对角线再进行翻转,最后就获得了旋转之后的矩阵。

三、代码

方法一 Java代码

class Solution {
    public void rotate(int[][] matrix) {
        int len = matrix.length;
        int[][] matrixCopy = new int[len][len];
        len -= 1;
        for (int i = 0; i <= len; i++) {
            for (int j = 0; j <= len; j++) {
                matrixCopy[i][j] = matrix[len - j][i];
            }
        }
        for (int i = 0; i <= len; i++) {
            for (int j = 0; j <= len; j++) {
                matrix[i][j] = matrixCopy[i][j];
            }
        }
    }
}

时间复杂度:O(N^2),一次遍历原矩阵元素添加旋转之后的元素到副本矩阵,一次遍历将副本矩阵元素复制替换到原矩阵。

空间复杂度:O(N^2),需要一个同等大小的副本矩阵存储旋转之后的元素。


方法二 Java代码

class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length - 1;
        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][i];
                matrix[n - j][i] = matrix[n - i][n - j];
                matrix[n - i][n - j] = matrix[j][n - i];
                matrix[j][n - i] = temp;
            }
        }
    }
}

时间复杂度:O(N^2),一次遍历原矩阵元素,按4个元素一组的规则两两交换元素。

空间复杂度:O(1),只需常数个额外空间。


方法三 Java代码

class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length - 1;
        for (int i = 0; i <= n / 2; ++i) {
            for (int j = 0; j <= n; ++j) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n - i][j];
                matrix[n - i][j] = temp;
            }
        }
        for (int i = 0; i <= n; ++i) {
            for (int j = 0; j <= i; ++j) {
                if (i == j) {
                    continue;
                }
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
    }
}

时间复杂度:O(N^2),一次遍历矩阵元素进行上下翻转,一次遍历矩阵元素进行住对角线翻转。

空间复杂度:O(1),只需常数个额外空间。


四、总结

只需要多观察例子的旋转,找出其中的规律即可。