Updated on August 26, 2021
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 6
- 3
- 0
- 7
- 4
- 1
- 8
- 5
- 2
Problem
Given a 2D array, rotate the array by 90 degrees.
Input
A
: 2D array of size greater than \times
Approach
This is a very commonly asked problem, with a conceptual approach that is easy to visualize but difficult to implement in code.
Optimized Solution
I encounter this problem many times over the years, often stumbling in the same way at the coding part.
The key to solving this problem lies in cleanliness. Yes, although the animated gif above shows how the rotation works conceptually, putting this into an algorithm can get very confusing simply due to the index and offset values that we have to keep juggling around.
If you are in the same category as I am, then my recommendations are as follows:
- Define a function solely for the rotation
- Have the rotation function take minimum and maximum boundaries of a square as inputs.
- For example,
r1
would represent the topmost row of the current inner square.r2
would represent the bottommost row.c1
would represent the leftmost column, andc2
would represent the rightmost column.
- For example,
- Have the rotation function also take an offset value, so that we can offset the rotation pattern like in the animation above.
The practical optimization for this problem is to just reduce the loop range by half as the square to process iteratively gets smaller and smaller until it reaches the middle. This part however is easier than the actual rotation algorithm itself.
Advanced Solutions
Let be the point in the original 2D matrix , where is the row number and is the column number. is the rotated matrix.
The key to solving this problem is to observe that a row in the original 2D array becomes a column in the rotated 2D array.
Lets look at the values in the first row.
And the second row:
We can see that and is mapped a certain way into .
- =
- =
The solutions below were written years ago and are still applicable for Pythonistas who like Python shortcuts (such as the ~
operator) to write as little code as possible. I would only recommend these if you fully understand how to solve this problem with the above approach.
Brute Force Solution
Note that ~j
is equivalent to -(j + 1)
. When used as an index of a list, it could also be interpreted as j + 1
values from the right.
This algorithm requires space complexity and time complexity
Approach #2
The optimized approach has a very straightforward strategy that you can follow. To rotate a matrix by 90 degrees, it takes two simple steps:
- Transpose the matrix (rows turn into columns, vice-versa)
- Flip the values of each row ()
Each step can be done as a separate nested for loop:
Approach #3
This solution reduces the need for two nested for loops, but it requires some tricky array manipulation and some Python tricks.
The idea is quite straightforward on a matrix:
- Cache the value of and set
- Cache the value of and set to the previous cached value
- Cache the value of and set to the previous cached value
- Set to the previous cached value
- Repeat with the inner rows/columns
Although this idea is straightforward, it will take a bit more effort to translate this into a formula.
One way to build up this formula is to try a few more example cases.
For example, on the first pass of a matrix, you will access these indices.
On the second pass, you will access these indices.
On the third pass, you will access these indices.
When do we stop swapping?
We stop swapping when we have successfully swapped each value in the leftmost, topmost, rightmost, and bottommost values. This could be labeled as the outermost cycle. Once this cycle is complete, we will have to start swapping again for the next innermost cycle.
In a matrix, we only need 1 cycle (the center value will never change!).
In a matrix, we need 2 cycles because the four center values can be rotated.
In a matrix, we need 2 cycles again; 1 cycle for the matrix in the center, and 1 cycle for the outermost boundary.
Thus, the number of cycles corresponds to the number of elements in a row or column: len(A) // 2