107 lines
3.1 KiB
Markdown
107 lines
3.1 KiB
Markdown
# 1.7. Matrix rotation
|
|
|
|
## Given an image represented by an NxN matrix, where each pixel is an integer, rotate the image by 90 degrees. Can you do this in place?
|
|
|
|
What's in place? in the same matrix? I could, but I'd have to save each row in a temporary variable, so I'd use O(n<sup>2</sup>) either way.
|
|
|
|
## First idea
|
|
|
|
I don't think this can be done in less than O(n<sup>2</sup>). It sounds like an easy thing in theory but you have to move all NxN integers around, even though the algorithm is easy it's still NxN numbers.
|
|
|
|
> Example: input format
|
|
|
|
```python
|
|
# python
|
|
imat = [[1,4,6],
|
|
[8,7,2],
|
|
[5,9,3]]
|
|
|
|
omat = [[5,8,1],
|
|
[9,7,4],
|
|
[3,2,6]]
|
|
```
|
|
|
|
```c++
|
|
// c
|
|
int input [N][N] = {1,4,6,8,7,2,5,9,3};
|
|
```
|
|
|
|
The algorithm would be:
|
|
|
|
```c++
|
|
int[N][N] rotate_matrix(int[N][N] mat, int N)
|
|
int newmat [N][N];
|
|
for (int i = 0; i < N; i++) {
|
|
for (int j = 0; j < N; j++) {
|
|
newmat[i][j] = mat[N - j][i];
|
|
}
|
|
}
|
|
return newmat;
|
|
}
|
|
```
|
|
|
|
How can the input be of size `[N][N]` if we still don't have that value?
|
|
|
|
```python
|
|
def rotate_matrix(mat, N):
|
|
newmat = []
|
|
for _ in range(N):
|
|
newmat.append([])
|
|
for i in range(N):
|
|
for j in range(N):
|
|
newmat[i][j].append(mat[n - j][i])
|
|
return newmat
|
|
```
|
|
|
|
It takes O(n + n<sup>2</sup>) in python.
|
|
|
|
## Hint
|
|
|
|
> Think about it as rotating layers, can you rotate a specific layer? Rotating a specific layer is just swapping the values in 4 arrays. If we can make the swap in 2 arrays, is it possible? And then generalize to 4 arrays?
|
|
|
|
Rotating a matrix is taking the 4 outermost layers/rows/columns, and swapping them. The middle number stays the same. We take the array in column [0], which is [1,8,5], reverse it, and paste it in the row [0]. Beforehand, save the row [0] in a temporary variable. Save all 4 outermost arrays in temp variables, and then swap. This takes O(4n) = O(n)
|
|
|
|
## Implementation
|
|
|
|
```c++
|
|
int temp [4][N];
|
|
for (int i = 0; i < N; i++) {
|
|
temp[0][i] = imat[0][i];
|
|
temp[1][i] = imat[i][2];
|
|
temp[2][i] = imat[2][i];
|
|
temp[3][i] = imat[i][0];
|
|
}
|
|
```
|
|
|
|
And then swap these 4 arrays:
|
|
|
|
```c++
|
|
for (int j = 0; j < N; j++) {
|
|
omat[0][i] = temp[3][i];
|
|
omat[i][2] = temp[0][i];
|
|
omat[2][i] = temp[1][i];
|
|
omat[i][0] = temp[2][i];
|
|
}
|
|
```
|
|
|
|
And this takes O(2(N + 4)) = O(N), and O(4N) = O(N) space. Damn it but this only works for N < 3, I have to rotate the inner layers as well, if there are some.
|
|
|
|
## Solution
|
|
|
|
Implement the rotation in layers. Circular rotation on each layer, moving the top edge to the right edge, the right to the bottom, the bottom to the left, and left to the top.
|
|
|
|
One option is copy the top edge to an array, move the left to the top, bottom to the left, and so on. But this requires O(N) memory.
|
|
|
|
Another way is to swap index by index.
|
|
|
|
```python
|
|
for i = 0 to n:
|
|
temp = top[i]
|
|
top[i] = left[i]
|
|
left[i] = bottom[i]
|
|
bottom[i] = right[i]
|
|
right[i] = temp
|
|
```
|
|
|
|
We do this swap on each layer, starting from the outermost layer and working our way inwards, or the other way around. The solution takes O(N<sup>2</sup>) time, any algorithm must touch all N<sup>2</sup> elements.
|