This is to rotate a matrix clockwise with 90 degree.
Solution 1: Naive rotate
Suppose the input is a n*n matrix. Then the ith row should be put to (n - 1 - i)th column.
For example n =3. Then 0th row to 2nd column. 1th row to 1th column. 2th row to 0th column.
We can create an empty matrix and move rows from original matrix to columns in this empty matrix.
void naive_rotate(vector<vector<int>>& matrix){
vector<vector<int>> temp(matrix.size(), vector<int>(matrix.size()));
for(int r = 0; r < matrix.size(); r ++){
int c = 0;
while(c<matrix.size()){
temp[c][matrix.size() - 1 - r] = matrix[r][c];
c++;
}
}
matrix = temp;
}
Solution 2: Rotate in place
From solution 1 we know that ith row would be moved to n-1-i th column.
How does it look like if we do so in place?
Example:
1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 |
Move the 0th row to 2nd column.
1 | 2 | 1 |
4 | 5 | 2 |
7 | 8 | 3 |
We have successfully created the new 3rd column. But up to this point, we have also lost the last elements of other rows. In the future these rows would not construct correct new columns. So we conclude that before we move, we have to store some values such that we won't lose any information in the future moves.
Moving a row at a time is complex. Let's try move 1 element. Say matrix[i][j].
2.1 Since ith row would be moved to n - 1 - ith column, matrix[i][j] would be moved to n - 1 - i th column.
2.2 Suppose when we rotate a horizontal row clockwise to a vertical column, the ith cell in the row would remain at ith cell in the column.
1 |
1 |
By 2.1 and 2.2, we conclude that matrix[i][j] would be moved to matrix[ j ][ n - 1 - i].
Now let's see what happens when we move matrix[i][j] to matrix[ n-1-j ][i].
(1) We record temp = matrix[ j][ n-1-i ] and matrix[i][j] moved to matrix[ j ][ n-1-i ].
(2) We need to put the record temp to its new place otherwise we lose it. Its original position is r = j, c = n-1-i, and its new position is r = n - 1 - i, c =n-1- j. Thus swap(temp, matrix[n-1-i][n-1-j]).
(3) now where should we put the new temp? Its original position is r = n-1-i, c =n-1- j and new position is r = n-1-j, i. Then swap( temp, matrx[ n-1-j ][ i ]).
(4) The original position of the new temp is r = n-1-j, c = i and new position is r = i, c = j. Note that we were first rotating matrix[i][j] and now we are back!
Thus we know that rotating mat[i][j] involves 4 swapping.
In conclusion every time we want to rotate mat[i][j], we need to do 4 swapping or otherwise we lose some values.
One extra thing to note is how the matrix changes during we rotate row by row using methods above.
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
As we finish rotating all elements in row 1, we get
13 | 9 | 5 | 1 |
14 | 6 | 7 | 2 |
15 | 10 | 11 | 3 |
16 | 12 | 8 | 4 |
We are just changing its border and the submatrix insider is not modified( {[6,7], [10,11]} ).
So we know that every time we rotate a row by methods above, we would modify only the border of the square-submatrix surrounded by the row.
Code:
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
in_place_rotate(matrix, 0,matrix.size()-1, matrix.size() );
}
void in_place_rotate(vector<vector<int>> &matrix,int r_start,int r_end, int matlen){
if(r_start>r_end - 1) return;//there is no submatrix any more.
for(int col = r_start; col<r_end;col++){//for current row, rotate all its components.
<span style="white-space:pre"> </span>//IT IS VERY IMPORTANT THAT col<r_end. We do not rotate mat[r_start][r_end]
<span style="white-space:pre"> </span>//since this position has been swapped with mat[r_start][r_start].
int i = r_start;
int j = col;
int count = 0;
int temp = matrix[i][j];//the component, mat[i][k], which we want to rotate
while(count < 3){//if we want to rotate one component, we need to take care of 4
//components since we are rotating in place
matrix[i][j] = matrix[matlen - 1 - j ][i];
j = matlen- 1 - j;
swap(i,j);
count++;
}
matrix[i][j] = temp;//the 4th swap
}
in_place_rotate(matrix, r_start + 1, r_end - 1,matlen);//go to the next submatrix surrounded by r_start + 1.
}
};