48. 旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
提示:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
原地算法:在计算机科学中,一个原地算法(in-place algorithm)是一种使用小的,固定数量的额外之空间来转换资料的算法。当算法执行时,输入的资料通常会被要输出的部分覆盖掉。不是原地算法有时候称为非原地(not-in-place)或不得其所(out-of-place)。
方法一:使用辅助数组
对于矩阵中的第三行和第四行同理。这样我们可以得到规律:
对于矩阵中第 ii行的第 j个元素,在旋转后,它出现在倒数第 i列的第 j个位置。
我们将其翻译成代码。由于矩阵中的行列从 0 开始计数,因此对于矩阵中的元素matrix[row][col],在旋转后,它的新位置为matrix new[col][n−row−1]。
这样以来,我们使用一个与 matrix 大小相同的辅助数组matrix new,临时存储旋转后的结果。我们遍历matrix 中的每一个元素,根据上述规则将该元素存放到matrix new 中对应的位置。在遍历完成之后,再将matrix new中的结果复制到原数组中即可。
前置知识点:
多维数组遍历:
package main
import (
"fmt"
)
func main() {
var f [2][3]int = [...][3]int{{1, 2, 3}, {7, 8, 9}}
for k1, v1 := range f {
for k2, v2 := range v1 {
fmt.Printf("(%d,%d)=%d ", k1, k2, v2)
}
fmt.Println()
}
}
输出结果:
(0,0)=1 (0,1)=2 (0,2)=3
(1,0)=7 (1,1)=8 (1,2)=9
func rotate(matrix [][]int) {
n := len(matrix)
tmp := make([][]int, n)
for i := range tmp{
tmp[i] = make([]int, n)
}
for i, row := range matrix{
for j, v := range row{
tmp[j][n - i - 1] = v;
}
}
copy(matrix, tmp)//matrix数组被tmp数组覆盖
}
方法二:原地旋转
题目中要求我们尝试在不使用额外内存空间的情况下进行矩阵的旋转,也就是说,我们需要「原地旋转」这个矩阵。那么我们如何在方法一的基础上完成原地旋转呢?
我们观察方法一中的关键等式:
matrix new[col][n−row−1]=matrix[row][col]
它阻止了我们进行原地旋转,这是因为如果我们直接将 matrix[row][col] 放到原矩阵中的目标位置 matrix[col][n−row−1]:matrix[col][n−row−1]=matrix[row][col]
原矩阵中的 matrix[col][n−row−1] 就被覆盖了!这并不是我们想要的结果。
因此我们可以考虑用一个临时变量temp 暂存matrix[col][n−row−1] 的值,这样虽然matrix[col][n−row−1] 被覆盖了,我们还是可以通过temp 获取它原来的值:
那么matrix[col][n−row−1] 经过旋转操作之后会到哪个位置呢?我们还是使用方法一中的关键等式,不过这次,我们需要将
带入关键等式,就可以得到:
matrix[n−row−1][n−col−1]=matrix[col][n−row−1]
同样地,直接赋值会覆盖掉matrix[n−row−1][n−col−1] 原来的值,因此我们还是需要使用一个临时变量进行存储,不过这次,我们可以直接使用之前的临时变量temp:
我们再重复一次之前的操作,matrix[n−row−1][n−col−1] 经过旋转操作之后会到哪个位置呢?
func rotate(matrix [][]int) {
n := len(matrix)
for i := 0; i < n / 2; i++{//蓝色区域对应的行
for j := 0; j < (n + 1) / 2; j++{//蓝色区域对应的列
//每次交换各个颜色区域的一个值
matrix[j][n - i - 1], matrix[n - i - 1][n - j - 1], matrix[n - j - 1][i],matrix[i][j] = matrix[i][j],matrix[j][n - i - 1], matrix[n - i - 1][n - j - 1], matrix[n - j - 1][i]
}
}
}
方法三:用翻转代替旋转
func rotate(matrix [][]int){
n := len(matrix)
//水平翻转
for i := 0; i < n / 2; i++{
matrix[i], matrix[n - i - 1] = matrix[n - i - 1],matrix[i]//一次交换一行
}
//主对角线翻转
for i := 0; i < n; i++{
for j := 0; j < i; j++{
matrix[i][j], matrix[j][i] = matrix[j][i],matrix[i][j]//交换关于主对角线对称的元素
}
}
}