题目
给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。
不占用额外内存空间能否做到?
示例 1:
给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-matrix-lcci
解题
该题的关键有两点: 1)旋转90°怎么做到?2)原地旋转不占用额外空间怎么做到?
简单来说,矩阵旋转90°其实就是: (“=>” 表示 “旋转至”)
1、矩阵的第一行 => 最后一列,第二行 => 倒数第二列…,最后一行 => 第一列
2、矩阵的第一列(从上往下) => 第一行(从右往左,但这是由于行变列翻转导致的,不影响),第二列 => 第二行…
即matrix[第i行][第j列] => matrix[第j行][第n+1-i列]
以上我们描述中起始和结束用的是第1行和第n行,开头末尾和为n+1;而在数组中索引是从0到n-1, 头尾和为n-1;所以代码中数组的公式其实是为matrix[i][j] => matrix[j][n-1-i]
因为不能占用额外内存空间, 所以不能创建另一个数组直接用公式将原数组输入进去
直接原地旋转
思路
1、通过旋转公式会发现:
matrix[i][j] => matrix[j][n-1-i] => matrix[ n-1-i][n-1-j] => matrix[n-1-j][i] => matrix[i][j]
四个元素正好依次旋转到下个位置循环一圈到原点
比交换(temp=a,a=b,b=temp)更复杂一点,这样的一个循环正好也可以只采用一个临时变量temp, 就完成原地的循环赋值变换:
temp = matrix[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] = temp
2、下一步就是一个矩阵中, 有几个圈 ? 需要枚举几个初始位置正好完成整个矩阵所有元素的旋转, 保证既不重复, 也不遗漏
因为一个循环有4个元素, 整个矩阵分为四块(左上、右上、右下、左下)整个矩阵有n2个元素, 所以每一块有n2/4个元素进行循环( n为偶数可以直接整除, n为奇数时剩一个不用旋转的中心点)
将左上=>右上=>右下=>左下=>左上。
枚举左上的那块子矩阵的所有元素进行上述旋转操作即可。
左上子矩阵为 n/2 x (n2/4)/(n/2) (这里的“/” 是java中的“/”向下取整) 分为不同情况就是如下方式:
① 当n为偶数时,子矩阵为 n/2 x n/2
② 当n为奇数时,子矩阵为(n-1)/2 x (n+1)/2
时间复杂度:O(n2)
空间复杂度:O(1)
代码
//不分奇偶数的写法
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
if(n == 0||n == 1){
return;
}
for(int i = 0; i < n/2; i++){
for(int j = 0; j < (n*n/4)/(n/2); j++){
int temp = matrix[i][j];
matrix[i][j] = matrix[n-1-j][i];
matrix