一、题目
给你一幅由N × N
矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。
不占用额外内存空间能否做到?给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 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、对于 NxN
的矩阵,进行矩阵变换时,第N行的每一列成为新的行的第一列;第(N-1)行的每一列成为新的行的第二列;以此类推,第1行的第一列成为新的导数第二行的倒数第二列。
理解:暴力解法,建立新的矩阵
原有矩阵A,其中数值与对应索引编号如下,
1 | 2 | 3 |
---|---|---|
[0,0] | [0,1] | [0,2 |
3 | 4 | 5 |
[1,0] | [1,1] | [1,2 |
7 | 8 | 9 |
[2,0] | [2,1] | [2,2 |
新建矩阵B,其数值与对应索引编号如下表示
7 | 4 | 1 |
---|---|---|
[0,0] | [0,1] | [0,2 |
8 | 5 | 2 |
[1,0] | [1,1] | [1,2 |
9 | 6 | 3 |
[2,0] | [2,1] | [2,2 |
模拟旋转过程
i=0,j = 0 , 将数值1旋转到矩阵B的第零行第二列, [ 0, 2 ] = [ 0, 0 ]
i=0, j=1, 将数值2旋转到矩阵B的第一行第二列, [ 1, 2 ] = [ 0, 1 ]
i=0, j=2, 将数值3旋转到矩阵B的第三行第二列, [ 3, 2 ] = [ 0, 2 ]
i=1, j = 0 , 将数值4旋转到矩阵B的第零行第一列, [ 0, 1] = [ 1, 0 ]
i=1, j=1, 将数值5旋转到矩阵B的第一行第一列, [ 1, 1 ] = [ 1, 1 ]
i=1, j=2, 将数值6旋转到矩阵B的第三行第一列, [ 2, 1 ] = [ 1, 2 ]
i=2, j = 0 , 将数值7旋转到矩阵B的第零行第零列, [ 0, 0 ] = [ 2, 0 ]
i=2, j=1, 将数值8旋转到矩阵B的第一行第零列, [ 1, 0 ] = [ 2, 1 ]
i=2, j=2, 将数值9旋转到矩阵B的第三行第零列, [ 2, 0 ] = [ 2, 2 ]
在上述过程中,新矩阵中的行数与j 相关,列数与i (n-1-i) 相关。也就是说,
// 伪代码
/*
for(i=0; i<n; j++ ){
for(j=0; j<n; j++){
B [j] [n-1-i] = A[i][j];
}
}
*/
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size(); // 矩阵matrix 的长度
auto matrixB = matrix; // vecotr 新建一个矩阵matrixB 大小维度与matrix 相同
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
matrixB[j][n-1-i] = matrix[i][j]; // 依次遍历交换不同索引处的数值
}
}
matrix = matrixB; // 将新的矩阵赋值给原矩阵matrix
}
};
原地解法
引入一个临时变量, temp.
在暴力解法中,我们已经知道一个关键变换关系,B[col][n-1-row] = A[row][col];
那么如果是同一个矩阵的话,写为A[col][n-1-row] = A[row][col]; 那么原来的值就会被覆盖掉。用Temp,存储这个新的数值,temp = A[col][n-1-row] 避免被覆盖掉;
那么就存在一个关键关系,在遍历的过程中
{
t
e
m
p
=
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
=
A
[
r
o
w
]
[
c
o
l
]
\left\{ \begin{aligned} temp = A[col][n-1-row] \\ A[col][n-1-row] = A[row][col]\\ \end{aligned} \right.
{temp=A[col][n−1−row]A[col][n−1−row]=A[row][col]
还是按照关键关系B[col][n-1-row] = A[row][col], 经过上述遍历过程之后,A[col][n-1-row]下一步应该变换为A[n-1-row][n-1-col]. 那么进一步的遍历关系可以写为
{ t e m p = A [ c o l ] [ n − 1 − r o w ] A [ c o l ] [ n − 1 − r o w ] = A [ r o w ] [ c o l ] A [ n − 1 − r o w ] [ n − 1 − c o l ] = A [ c o l ] [ n − 1 − r o w ] \left\{ \begin{aligned} temp = A[col][n-1-row] \\ A[col][n-1-row] = A[row][col]\\ A[n-1-row][n-1-col] = A[col][n-1-row] \\ \end{aligned} \right. ⎩⎪⎨⎪⎧temp=A[col][n−1−row]A[col][n−1−row]=A[row][col]A[n−1−row][n−1−col]=A[col][n−1−row]
进一步的,当前变换为A[n-1-row][n-1-col],按照关键变换关系B[col][n-1-row] = A[row][col], A[n-1-row][n-1-col]下一步应该变换为
A[n-1-row][n-1-col]=A[n-1-col][n-1-(n-1-row)]=A[n-1-col][row]. 进一步的遍历关系可以写为
{
t
e
m
p
=
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
=
A
[
r
o
w
]
[
c
o
l
]
A
[
n
−
1
−
r
o
w
]
[
n
−
1
−
c
o
l
]
=
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
A
[
n
−
1
−
c
o
l
]
[
r
o
w
]
=
A
[
n
−
1
−
r
o
w
]
[
n
−
1
−
c
o
l
]
\left\{ \begin{aligned} temp = A[col][n-1-row] \\ A[col][n-1-row] = A[row][col]\\ A[n-1-row][n-1-col] = A[col][n-1-row] \\ A[n-1-col][row]=A[n-1-row][n-1-col] \\ \end{aligned} \right.
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧temp=A[col][n−1−row]A[col][n−1−row]=A[row][col]A[n−1−row][n−1−col]=A[col][n−1−row]A[n−1−col][row]=A[n−1−row][n−1−col]
将当前旋转的结果A[n-1-col][row],按照关键变换关系B[col][n-1-row] = A[row][col], A[n-1-col][row]下一步变换为A[n-1-col][row] = A[n-1-(n-1-col)][row] = A[col][row]. 那么,遍历关系进一步的可以写为
{
t
e
m
p
=
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
=
A
[
r
o
w
]
[
c
o
l
]
A
[
n
−
1
−
r
o
w
]
[
n
−
1
−
c
o
l
]
=
A
[
c
o
l
]
[
n
−
1
−
r
o
w
]
A
[
n
−
1
−
c
o
l
]
[
r
o
w
]
=
A
[
n
−
1
−
r
o
w
]
[
n
−
1
−
c
o
l
]
A
[
c
o
l
]
[
r
o
w
]
=
A
[
n
−
1
−
c
o
l
]
[
r
o
w
]
\left\{ \begin{aligned} temp = A[col][n-1-row] \\ A[col][n-1-row] = A[row][col]\\ A[n-1-row][n-1-col] = A[col][n-1-row] \\ A[n-1-col][row]=A[n-1-row][n-1-col] \\ A[col][row] = A[n-1-col][row]\\ \end{aligned} \right.
⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧temp=A[col][n−1−row]A[col][n−1−row]=A[row][col]A[n−1−row][n−1−col]=A[col][n−1−row]A[n−1−col][row]=A[n−1−row][n−1−col]A[col][row]=A[n−1−col][row]
依次类推,目的是最终实现
{
t
e
m
p
=
A
[
r
o
w
]
[
c
o
l
]
A
[
r
o
w
]
[
c
o
l
]
=
t
e
m
p
\left\{ \begin{aligned} temp = A[row][col]\\ A[row][col] = temp\\ \end{aligned} \right.
{temp=A[row][col]A[row][col]=temp
相互交换。
上述讲述的是原地交换的原理,那么如何实现位置交换?
(暂时还没有明白其中的思想,等待某一天的悟性!!!
)
- 当 nn 为偶数时,我们需要枚举 n 2 / 4 = ( n / 2 ) × ( n / 2 ) n 2 / 4 = ( n / 2 ) × ( n / 2 ) n^2 / 4 = (n/2) \times (n/2)n 2 /4=(n/2)×(n/2) n2/4=(n/2)×(n/2)n2/4=(n/2)×(n/2)个位置(针对4X4 的矩阵而言)
- 当 nn 为奇数时,由于中心的位置经过旋转后位置不变,我们需要枚举 ( n 2 − 1 ) / 4 = ( ( n − 1 ) / 2 ) × ( ( n + 1 ) / 2 ) ( n 2 − 1 ) / 4 = ( ( n − 1 ) / 2 ) × ( ( n + 1 ) / 2 ) (n^2-1) / 4 = ((n-1)/2) \times ((n+1)/2)(n 2 −1)/4=((n−1)/2)×((n+1)/2) (n2−1)/4=((n−1)/2)×((n+1)/2)(n2−1)/4=((n−1)/2)×((n+1)/2)个位置
// 放上官方给出的答案!!
// 小菜目前还未完成这个代码的理解!!!
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
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 - 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;
}
}
}
};