48. Rotate Image
Difficulty: Medium
You are given an n x n 2D matrix representing an image.
Rotate the image by 90 degrees (clockwise).
Note:
You have to rotate the image , which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.
Example 1:
Given input matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
rotate the input matrix in-place such that it becomes:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
Example 2:
Given input matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],
rotate the input matrix in-place such that it becomes:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]
解题思路
解题先从简单的case来想,如果n = 1的话,我们不需要移动
如果n = 2的话,矩阵的转变如下
1 2 => 3 1
3 4 => 4 2
我们想要知道的不是1从原本的m[0][0]去到了哪个新的位置(无论是去了m[0][1]好,m[1][1]也好),而是要知道后上位的坐标原本在哪个位置才能推断出规律(我觉得是懂了此理的话,解法同样适用于180度,270度,etc)
1的位置的坐标m[0][0] = m[1][0]新上位的数字的旧坐标
m[0][1] = m[0][0]
m[1][0] = m[1][1]
m[1][1] = m[0][1]
可得出的规律是m[i][j] = m[n - 1 - j][i]
继续在n = 3,4,5也能验证这个规律的真实性
在这里可以得出解法1
但是解法1在空间上并不能满足我们,如果我们想要in-place更改的话,我们需要一次更改四个坐标,这里可以用一个temp变量
已知m[i][j] = m[n - 1 - j][i]
所以四个角的坐标如下
m[i][j]
m[n - 1 - j][i]
m[n - 1 - i][n - 1 - j] (以前我到这里就看不懂为什么了,找了很多博客也不明白,后来挣扎了一会儿才知道这里的i和j其实全就是按照那个规律来plug in而已- -)
m[n - 1 - (n - 1 - j)][n - 1 - i] = m[j][n - 1 -i]
当我们知道四个角的坐标之后我们还需要知道每次要移动的坐标,不像解法1可以直接全部过一遍,一开始我也是完全不知道博客大神们在讲什么,所以从n = 1开始写了起来
n = 1,不需要移动
n = 2,移动m[0][0]
n = 3,移动m[0][0], m[0][1]
n = 4,移动m[0][0], m[0][1], m[0][2], m[1][1]
n = 5,移动m[0][0], m[0][1], m[0][2], m[0][3], m[1][1], m[1][2]
n = 6,移动m[0][0], m[0][1], m[0][2], m[0][3], m[0][4], m[1][1], m[1][2], m[1][3], m[2][2]
(是的我比较愚笨所以不把规律写全一些怕漏掉信息。。)
从这个规律上可见i < n / 2
而j最多也只是会去到n - 1 - i(i <= j < n - 1 - i),这里的i可以认为是每一次一圈正方形的外层的偏离量。比如第一个大圈的偏离量是0,0,所以i是0。下一个小圈的偏离量是在1, 1,所以i是1。每次走圈圈的时候,j必定不会比n - 1 - i大,因为i每次都在增大,而j不可能在小圈的时候走回到大圈
下图是我的解法2的走路规律
由此可得解法2
Solution
Language: Java
class 解法1 {
// Time: O(n^2)
// Space: O(n^2)
public void rotate(int[][] matrix) {
int n = matrix.length;
int[][] m = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
m[i][j] = matrix[n - 1 - j][i];
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = m[i][j];
}
}
}
}
class 解法2 {
// Time: O(n^2)
// Space: O(1)
public void rotate(int[][] matrix) {
int n = m.length;
for (int i = 0; i < n / 2; i++) {
for (int j = i; j < n - 1 - i; j++) {
int temp = m[i][j];
m[i][j] = m[n - 1 - j][i];
m[n - 1 - j][i] = m[n - 1 - i][n - 1 - j];
m[n - 1 - i][n - 1 -j] = m[j][n - 1 - i];
m[j][n - 1 - i] = temp;
}
}
}
}