LeetCode 48. 旋转图像(旋转矩阵)三种解法

## 48. 旋转图像(旋转矩阵)
难度:Medium
语言:Java

题目

给定一个 n × n 的二维矩阵表示一个图像。将图像顺时针旋转 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]
]

解法1(非原地旋转,借助辅助数组)

思路

先来一个笨办法,借用辅助数组,但不符合题目原地旋转的要求。
根据3x3的矩阵和4x4的矩阵旋转后得到的图像来找规律,可以发现规律:
matrix_new[col][N-row-1] = matrix[row][col]

代码

class Solution1 {
    public void rotate(int[][] matrix) {
        int i, j, N = matrix.length;
        int[][] matrix_new = new int[N][N];
        for (i=0; i<N; i++)
            for (j=0; j<N; j++)
            	//key:  matrix_new[col][N-row-1] = matrix[row][col]
                matrix_new[j][N-i-1] = matrix[i][j]; 
        for (i=0; i<N; i++)
            for (j=0; j<N; j++)
                matrix[i][j] = matrix_new[i][j];
    }
}

复杂度分析
时间复杂度:O(N^2),其中N是matrix的边长。
空间复杂度:O(N^2)。我们需要使用一个和 matrix大小相同的辅助数组。

解法2(官方题解,原地旋转)

思路

根据3x3的矩阵和4x4的矩阵旋转后得到的图像来找规律,可以发现规律:
matrix_new[col][N-row-1] = matrix[row][col]
原地旋转就是要求不创建新矩阵matrix_new,在原有矩阵matrix的基础上进行旋转,这就需要用到一个临时变量:int temp,防止换值时,原来的值被覆盖而丢失。

已知换值的关键等式:
matrix[col][N-row-1] = matrix[row][col]

为了防止**matrix_new[col][N-row-1]**被覆盖,用一个临时变量 temp 暂存matrix_new[col][N-row-1]的值。

temp = matrix[col][N-row-1]
matrix[col][N-row-1] = matrix[row][col]

那么旋转后matrix_new[col][N-row-1]又去了哪里呢?我们根据上面的关键等式,可得到变换关系:

//重要变换等式!!!
row = col
col = N - row - 1

带入关键等式,可得到

matrix[N−row−1][N−col−1]=matrix[col][N−row−1]

为了保存matrix[N−row−1][N−col−1]的值,使用刚才的临时变量temp,这样的话,temp保存了matrix[N−row−1][N−col−1]的值,而给matrix[N−row−1][N−col−1]赋值为matrix[col][N−row−1],使得matrix[col][N−row−1]的值没有丢失,已经取出后,再将matrix[col][N−row−1]赋值给matrix[row][col]

temp = matrix[N−row−1][N−col−1]
matrix[N−row−1][N−col−1] = matrix[col][N−row−1]
matrix[col][N−row−1] = matrix[row][col]

那么,matrix[N−row−1][N−col−1]又旋转去了哪里呢?以此类推

temp = matrix[N-col-1][row]
matrix[N-col-1][row] = matrix[N−row−1][N−col−1]
matrix[N−row−1][N−col−1] = matrix[col][N−row−1]
matrix[col][N−row−1] = matrix[row][col]

matrix[N-col-1][row]又旋转去了哪里呢?再来一次

temp = matrix[row][col]
matrix[row][col] = matrix[N-col-1][row]
matrix[N-col-1][row] = matrix[N−row−1][N−col−1]
matrix[N−row−1][N−col−1] = matrix[col][N−row−1]
matrix[col][N−row−1] = matrix[row][col]

到此为止,我们可以发现已经出现了一个闭合回路,这四项处于一个循环中,并且每一项旋转后的位置就是下一项所在的位置。因此我们可以使用一个临时变量 temp 完成这四项的原地交换:

temp = matrix[row][col]
matrix[row][col] = matrix[N-col-1][row]
matrix[N-col-1][row] = matrix[N−row−1][N−col−1]
matrix[N−row−1][N−col−1] = matrix[col][N−row−1]
matrix[col][N−row−1] = temp

现在已经知道了如何原地旋转矩阵,还有一个重要的问题在于:应该枚举哪些位置进行上述的原地交换操作呢?由于每一次原地交换四个位置,因此可以将矩阵均分为四部分:

  • 当n为偶数时,需要枚举 n2 / 4个位置,如下图所示,只用枚举蓝色区域:
    用 for 循环表示为:
for (int i=0; i<n/2; i++){ // 行
	for(int j=0; j<n/2; j++){ // 列
		//此处进行旋转操作
	}
}

在这里插入图片描述

  • 当n为奇数时,中心点不用旋转,需要枚举 (n2 - 1) / 4 个位置,如下图所示,只用枚举蓝色区域:
    用 for 循环表示为:
for (int i=0; i<n/2; i++){ // 行
	for(int j=0; j<(n+1)/2; j++){ // 列
		//此处进行旋转操作
	}
}

在这里插入图片描述
由以上两种情况的 for 循环可发现,两种情况可以合并:

for (int i=0; i<n/2; i++){ // 行,当 n 为 5 时,5 / 2 = 2
	for(int j=0; j<(n+1)/2; j++){ // 列
		//当 n 为 5 时, (5 + 1) / 2 = 3; 当 n 为 4 时, (4 + 1) / 2 = 2;
		//此处进行旋转操作
	}
}

代码

class Solution2 {
    public void rotate(int[][] matrix) {
        int i, j, temp, N = matrix.length;
        for (i=0; i<(N+1)/2; i++)
            for (j=0; j<N/2; j++){
                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;
            }
    }
}

解法3(原地旋转,先转置再水平翻转)

思路

一个矩阵沿着左上到右下的对角线翻转(先转置),然后再水平翻转即将矩阵沿垂直中线反转,就可以等同于顺时针旋转90°

代码

class Solution {
    public void rotate(int[][] matrix) {
        int i, j, temp, N = matrix.length;//二维数组的length等于行数
        // 转置数组
        for (i=0; i<N; i++){
            for (j=i; j<N; j++){
                temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        // 水平翻转
        for (i=0; i<N; i++){
            for (j=0; j<N/2; j++){
                temp = matrix[i][j];
                matrix[i][j] = matrix[i][N-1-j];
                matrix[i][N-1-j] = temp;
            }
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值