parent
d667782f5c
commit
2e9b3f244f
|
|
@ -0,0 +1,34 @@
|
|||
public static boolean rotate(int[][] matrix) {
|
||||
int n = matrix.length;
|
||||
if (n == 0 || n != matrix[0].length) return false; // Not a square
|
||||
|
||||
for (int layer = 0; layer < n/2; layer++) {
|
||||
int first = layer;
|
||||
int last = n - 1 - layer;
|
||||
for(int i = first; i < last; i++) {
|
||||
int offset = i - first;
|
||||
int top = matrix[first][i]; // save top
|
||||
|
||||
// left -> top
|
||||
matrix[first][i] = matrix[last-offset][first];
|
||||
|
||||
// bottom -> left
|
||||
matrix[last-offset][first] = matrix[last][last - offset];
|
||||
|
||||
// right -> bottom
|
||||
matrix[last][last - offset] = matrix[i][last];
|
||||
|
||||
// top -> right
|
||||
matrix[i][last] = top; // right <- saved top
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[][] matrix = AssortedMethods.randomMatrix(3, 3, 0, 9);
|
||||
AssortedMethods.printMatrix(matrix);
|
||||
rotate(matrix);
|
||||
System.out.println();
|
||||
AssortedMethods.printMatrix(matrix);
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
# 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.
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import unittest
|
||||
|
||||
def rotate_matrix(matrix):
|
||||
'''rotates a matrix 90 degrees clockwise'''
|
||||
n = len(matrix)
|
||||
for layer in range(n // 2):
|
||||
first, last = layer, n - layer - 1
|
||||
for i in range(first, last):
|
||||
# save top
|
||||
top = matrix[layer][i]
|
||||
|
||||
# left -> top
|
||||
matrix[layer][i] = matrix[-i - 1][layer]
|
||||
|
||||
# bottom -> left
|
||||
matrix[-i - 1][layer] = matrix[-layer - 1][-i - 1]
|
||||
|
||||
# right -> bottom
|
||||
matrix[-layer - 1][-i - 1] = matrix[i][- layer - 1]
|
||||
|
||||
# top -> right
|
||||
matrix[i][- layer - 1] = top
|
||||
return matrix
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
'''Test Cases'''
|
||||
data = [
|
||||
([
|
||||
[1, 2, 3, 4, 5],
|
||||
[6, 7, 8, 9, 10],
|
||||
[11, 12, 13, 14, 15],
|
||||
[16, 17, 18, 19, 20],
|
||||
[21, 22, 23, 24, 25]
|
||||
], [
|
||||
[21, 16, 11, 6, 1],
|
||||
[22, 17, 12, 7, 2],
|
||||
[23, 18, 13, 8, 3],
|
||||
[24, 19, 14, 9, 4],
|
||||
[25, 20, 15, 10, 5]
|
||||
])
|
||||
]
|
||||
|
||||
def test_rotate_matrix(self):
|
||||
for test_matrix, expected in self.data:
|
||||
actual = rotate_matrix(test_matrix)
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Reference in New Issue