给定一个 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
题目要求不借助辅助矩阵,通过在原矩阵中直接原地修改,实现**空间复杂度 O(1)**的解法。
以位于矩阵四个角点的元素为例,设矩阵左上角元素 A 、右上角元素 B 、右下角元素 C 、左下角元素 D 。矩阵旋转 90º 后,相当于依次先后执行D→A , C→D , B→C ,A→B 修改元素,即如下「首尾相接」的元素旋转操作:
A←D←C←B←A
如上图所示,由于第 1 步D→A 已经将 A 覆盖(导致 A 丢失),此丢失导致最后第 4步 A→B 无法赋值。为解决此问题,考虑借助一个辅助变量 tmp预先存储 A ,此时的旋转操作变为:
暂存 tmp=A
A←D←C←B←tmp
一轮可以完成矩阵 4 个元素的旋转。因而,只要分别以矩阵左上角 1/4的各元素为起始点执行以上旋转操作,即可完整实现矩阵旋转。
具体来看,当矩阵大小n为偶数时,取前n/2行、前n/2列的元素为起始点;当矩阵大小n为奇数时,取前n/2行、前(n+1)/2列的元素为起始点。
以示例二为例,图片具体流程如下:参考地址
分别以矩阵左上角的那4个元素为起点,总共进行4轮旋转
第一轮旋转:以元素5(坐标为matrix[0][0])为起点进行旋转,元素5暂存于tmp。
第二轮旋转:以元素1(坐标为matrix[0][1])为起点进行旋转,元素1暂存于tmp。
第三轮旋转:以元素2(坐标为matrix[1][0])为起点进行旋转,元素2暂存于tmp。
第四轮旋转:以元素4(坐标为matrix[1][1])为起点进行旋转,元素4暂存于tmp。
至此,矩阵顺时针旋转90°完成。
代码实现:
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
# 设矩阵行列数为 n
n = len(matrix)
# 起始点范围为 0 <= i < n // 2 , 0 <= j < (n + 1) // 2
# 其中 '//' 为整数除法
for i in range(n // 2):
for j in range((n + 1) // 2):
print('i',i)
print('j',j)
# 暂存 A 至 tmp
tmp = matrix[i][j]
# 元素旋转操作 A <- D <- C <- B <- tmp
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] = tmp
注:
示例一为三阶矩阵,那么n=3,for i in range(n // 2)和for j in range((n + 1) // 2),分别表示i只取0,j取0和1。
示例二为四阶矩阵,那么n=4,for i in range(n // 2)和for j in range((n + 1) // 2),分别表示i取0和1,j取0和1。