Yes, that code is pretty ugly and hard to read - primarily because the author didn't use very descriptive variable names. I solved that same problem using the same principles (treating the square matrix as a set of concentric squares and then rotating one at a time going from the outer square to the inner square). Here is my solution and the explanation of my thought process.
The Code
I used C#, but the syntax is nearly identical to Java. After copy/pasting, just change a.Length to a.length and it should be syntactically correct Java.
void swap(int[][] a, int g, int h, int i, int j) {
int temp = a[g][h];
a[g][h] = a[i][j];
a[i][j] = temp;
}
int[][] rotateImage(int[][] a) {
if (a.Length > 1) {
int topRow = 0, bottomRow = a.Length - 1, leftCol = topRow, rightCol = bottomRow;
while (topRow < bottomRow && leftCol < rightCol) {
swap(a, topRow, leftCol, topRow, rightCol);
swap(a, topRow, leftCol, bottomRow, leftCol);
swap(a, bottomRow, leftCol, bottomRow, rightCol);
for (int i = topRow + 1, j = bottomRow - 1; i < bottomRow && j > topRow; i++, j--) {
swap(a, topRow, i, i, rightCol);
swap(a, topRow, i, bottomRow, j);
swap(a, topRow, i, j, leftCol);
}
topRow++; leftCol++;
bottomRow--; rightCol--;
}
}
return a;
}
You may notice that I could potentially get rid of the variables leftCol and rightCol since they are kept equal to topRow and bottomRow respectfully. The reason that I don't is because I feel it makes the code easier to follow.
The Explanation
First, note that if given a 1x1 matrix, we return the original matrix because there is only one pixel which means no rotation is necessary.
Next, imagine we are given the following 2x2 matrix:
1 2
3 4
You could rotate this matrix in three swaps. Top Left -> Top Right, Top Left -> Bottom Left, and Top Left -> Bottom Right.
4 1
2 3
Now imagine we are given the following 3x3 matrix:
1 2 3
4 5 6
7 8 9
Note that the inner square is our old friend the 1x1 matrix. It's important to realize that all square matrices where n > 1 && n % 2 != 0 will eventually reduce down to a 1x1 in the center. Similarly, those where n > 1 && n % 2 == 0 will reduce down to a 2x2 in the center. We can handle both cases the same way.
Again, we will start with the corners of the outer square. We use our familiar previous three swaps: Top Left -> Top Right, Top Left -> Bottom Left, and Top Left -> Bottom Right.
7 2 1
4 5 6
9 8 3
Notice that the matrix is almost rotated; it's just those four pesky values in the centers of the exterior sides. But, also notice that each of those values are just one position away from the corners we rotated. If we continue our pattern of using a fixed starting point for our swaps the same way we did the corners, we could rotate the last four values like so: Top Middle -> Right Middle, Top Middle -> Bottom Middle, and Top Middle -> Left Middle. In terms of indices, "Top Middle" is just "Top Left" plus one. Similarly, "Right Middle" is just "Top Right" plus one. For some of the indices, it makes sense to start at the extreme large index (n - 1) and decrement. I refer to the smaller middle index as i and the larger middle index as j.
7 4 1
8 5 2
9 6 3
It takes three swaps to rotate a 2x2 matrix, six swaps to rotate a 3x3 matrix, and in general it takes n! swaps to rotate a nxn matrix. My while loop rotates the corners for each concentric square in the matrix (and each square is smaller than the previous square), and then my for loop takes care of the values in-between the corners along the edges. It continues like this until either there are no more interior squares to rotate, or the only interior square remaining is a 1x1 matrix.