Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Rotate an n×n matrix 90° clockwise in place. The cheap-but-wasteful answer copies into a second matrix with the mapping new[j][n−1−i] = old[i][j]. The interview answer uses the identity 90° clockwise = transpose, then reverse each row — both done in place for O(1) extra space.
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you can manipulate 2D indices without getting lost, and whether you know the transpose+reverse decomposition that turns a scary-looking rotation into two trivial passes — in place.
Where candidates slip
Allocating a second matrix when the prompt says in place, or transposing over the full grid (j from 0) which swaps every pair twice and leaves the matrix unchanged.
How to stand out
Derive new[j][n−1−i] = old[i][j] out loud, then say 'that's exactly transpose followed by reversing each row' — showing you understand WHY the trick works, not that you memorised it.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewRotate an n×n matrix 90° CWIn-place required?NoYesExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Copy Into a New Matrix (Index Map)
1Hint 1Explore hintHide hint
Where does the element at (i, j) go after a 90° clockwise turn? Trace one corner — the top-left (0,0) ends up at the top-right.
2Hint 2Explore hintHide hint
Work out the formula: a clockwise rotation sends (row i, col j) to (row j, col n−1−i). Build a fresh matrix using that map.
3Hint 3Explore hintHide hint
Allocate result[n][n], write result[j][n−1−i] = matrix[i][j] for every cell, then (if you must mutate) copy result back into matrix.
A · Core idea
Build the answer in a brand-new matrix using the closed-form coordinate map, then (if the signature mutates in place) copy it back. The whole approach hinges on one formula.
Deriving the map is the real work. Picture the top row sliding to the right edge: the element at (0, 0) lands at (0, n−1), and (0, 1) lands at (1, n−1). Generalising, the cell at (i, j) moves to (j, n−1−i). Equivalently, the cell that ends up at (r, c) came from (n−1−c, r). Pick one direction and write it consistently — mixing the two is the classic off-by-rotation bug.
Why it's the natural first attempt. With a spare matrix there's no aliasing to worry about: every write goes to a clean cell, so you never clobber a value you still need to read. It's the version you can get correct under pressure, and stating it proves you understand the target of the rotation before you optimise the storage away.
Why we don't ship it. It allocates a second n×n grid — precisely the thing the problem bans. It's here to pin down the index map; the in-place approach reuses that same geometric insight while spending O(1) extra space.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
matrix = [[1,2,3],[4,5,6],[7,8,9]]Array state
row 0 before
elements 1,2,3 sit in the top row
[[7,4,1],[8,5,2],[9,6,3]]C · Code with teaching comments
Reference implementation previewpublic void rotate(int[][] matrix) { int n = matrix.length; int[][] result = new int[n][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) {Explore the full codeHide the full code
D · Why it works and complexityO(n²) timeO(n²) spaceOpen the invariant and proofExplore the proofHide the proof
The entire rotation is captured by one line: new[j][n−1−i] = old[i][j]. Everything clever that follows is just a way to realise that same permutation of cells without a second buffer. Get this map right and the optimal version is a two-step reflection of it.
ComplexityO(n²) time, O(n²) space — Every one of the n² cells is read once and written once → O(n²) time. The second matrix is n² cells → O(n²) space, which is exactly what the prompt forbids.
E · Edge cases and pitfalls4matrix = [[1]] — n=1: the single map (0,0)→(0,0) is a no-op; result equals input.Explore edge casesHide edge cases
Edge cases handled
matrix = [[1]]n=1: the single map (0,0)→(0,0) is a no-op; result equals input.
Pitfalls
- Allocating result[][] — directly violates the 'no second matrix' constraint.
- Using new[i][n−1−j] instead of new[j][n−1−i] — that's a counter-clockwise / reflected rotation.
- In Python writing matrix[i] = result[i] (rebinds the row) instead of matrix[i][:] = result[i] (mutates in place).
Approach 2 of 2 · Optimal
Transpose + Reverse Each Row (Optimal, In Place)
1Hint 1Explore hintHide hint
A rotation feels hard, but reflections are easy and in place. Can you build the rotation out of two reflections?
2Hint 2Explore hintHide hint
Transpose the matrix (swap M[i][j] with M[j][i]) — that flips it across the main diagonal. Now compare to the target: what single extra reflection finishes the job?
3Hint 3Explore hintHide hint
After transposing, reverse each row left-to-right. Transpose + horizontal mirror = 90° clockwise. Both steps mutate the matrix directly, so no extra grid.
A · Core idea
Do the rotation as two in-place reflections. First transpose the matrix across its main diagonal, then reverse each row. The composition of those two reflections is exactly a 90° clockwise rotation.
Why transpose-then-reverse equals a clockwise rotation. Transposing sends (i, j) to (j, i) — a flip across the main diagonal. Reversing each row then sends (j, i) to (j, n−1−i). Compose them and the cell at (i, j) lands at (j, n−1−i) — the very map we derived in the first approach. Two cheap, in-place reflections multiply out to the one expensive-looking rotation. (Counter-clockwise is the same idea: transpose, then reverse each column.)
Why the transpose loop starts at `j = i + 1`. The transpose swaps M[i][j] with M[j][i]. If the inner loop ran j from 0, you'd hit each off-diagonal pair twice — once as (i, j) and again as (j, i) — and the second swap would put everything back, leaving the matrix unchanged. Starting j at i + 1 visits each pair exactly once and skips the diagonal (where i == j and the swap is pointless). This is the single most common bug in the whole problem.
Why it's strictly better. It's the same O(n²) cell-touches as the copy approach, but with no second grid — O(1) extra space, satisfying the constraint that defines the problem. And it generalises: swap the reversal step and you get every other right-angle rotation for free.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
matrix = [[1,2,3],[4,5,6],[7,8,9]]Array state
original row 0
top row before any work
[[7,4,1],[8,5,2],[9,6,3]]C · Code with teaching comments
D · Why it works and complexityO(n²) timeO(1) spaceOpen the invariant and proofExplore the proofHide the proof
Rotations are intimidating; reflections are trivial. The trick is realising any 90° rotation factors into two reflections you can do in place — a diagonal flip (transpose) and an axis flip (row reverse). Decomposing a hard transform into a product of easy ones is a reusable problem-solving move, not a Rotate-Image-only gimmick.
ComplexityO(n²) time, O(1) space — Transpose touches each of the ~n²/2 upper-triangle pairs once; reversing all rows is another n²/2 swaps. Total O(n²) time, and every swap is in place so O(1) extra space.
E · Edge cases and pitfalls5matrix = [[1]] — n=1: transpose loop never runs (no j>i), row reverse is a no-op → matrix unchanged, which is correct.Explore edge casesHide edge cases
Edge cases handled
matrix = [[1]]n=1: transpose loop never runs (no j>i), row reverse is a no-op → matrix unchanged, which is correct.matrix = [[1,2],[3,4]]Transpose → [[1,3],[2,4]]; reverse rows → [[3,1],[4,2]], the correct 90° clockwise result.
Pitfalls
- Inner loop j from 0 instead of i+1 — swaps every pair twice and leaves the matrix unchanged.
- Reversing each row for counter-clockwise — CCW needs reversing the rows' order (or each column) instead.
- Reversing first then transposing — order matters; that produces a reflection, not a clean rotation.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic void rotate(int[][] matrix) { int n = matrix.length; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int tmp = matrix[i][j];Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Transposing over the full grid (double swap)
Running the inner loop from j=0 swaps (i,j) and later (j,i) as well, so every off-diagonal pair is exchanged twice and ends up back where it started — the matrix looks untouched.
Explore the code comparisonHide the code comparison
Transposing over the full grid (double swap)
Running the inner loop from j=0 swaps (i,j) and later (j,i) as well, so every off-diagonal pair is exchanged twice and ends up back where it started — the matrix looks untouched.
Don't write this
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) { // j = 0 → double swap
int tmp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = tmp;
}
}Write this instead
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) { // upper triangle only
int tmp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = tmp;
}
}2Mixing up clockwise and counter-clockwise
Transpose-then-reverse-rows is clockwise. To go counter-clockwise you transpose then reverse the order of the rows (or reverse each column). Reversing the wrong axis silently produces the mirror of the intended rotation.
Explore the code comparisonHide the code comparison
Mixing up clockwise and counter-clockwise
Transpose-then-reverse-rows is clockwise. To go counter-clockwise you transpose then reverse the order of the rows (or reverse each column). Reversing the wrong axis silently produces the mirror of the intended rotation.
Don't write this
for i in range(n):
for j in range(i + 1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
matrix.reverse() # reverses ROW ORDER → counter-clockwiseWrite this instead
for i in range(n):
for j in range(i + 1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for row in matrix:
row.reverse() # reverses EACH ROW → clockwise3Returning a new matrix instead of mutating
The signature returns void / None — the grader inspects the original object. Building and returning a fresh grid leaves the input untouched and fails even though the values are 'right'.
Explore the code comparisonHide the code comparison
Returning a new matrix instead of mutating
The signature returns void / None — the grader inspects the original object. Building and returning a fresh grid leaves the input untouched and fails even though the values are 'right'.
Don't write this
def rotate(self, matrix):
n = len(matrix)
return [[matrix[n - 1 - j][i] for j in range(n)] for i in range(n)]Write this instead
def rotate(self, matrix):
n = len(matrix)
for i in range(n):
for j in range(i + 1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for row in matrix:
row.reverse()Revise
Carry the pattern into the interview
Pattern to remember
In-place matrix rotation via transpose + row reversal
Code pattern to memorize
transpose: for i in 0..n: for j in i+1..n: swap(M[i][j], M[j][i])
reverse each row: for each row: row.reverse()
# 90° clockwise = transpose then mirror horizontallyRules to remember
- 190° clockwise = transpose, then reverse each row. 90° counter-clockwise = transpose, then reverse each column (or reverse rows first).
- 2Transpose with the inner loop starting at
j = i + 1, notj = 0— touching the lower triangle too swaps every pair twice and undoes the transpose. - 3It must be in place: mutate the input matrix, don't return a new one. Returning a copy is the trap the prompt is built to catch.
- 4The matrix is square (n×n). The transpose trick relies on that; a non-square matrix can't be rotated in place into the same buffer.
- 5Derive the index map
new[j][n−1−i] = old[i][j]on the board first — it's how you prove the transpose+reverse identity instead of memorising it.
Use this pattern when
- Square matrix, rotate / reflect / transpose by a fixed angle
- Interviewer adds 'do it in place' or 'O(1) extra space'
- Coordinates map to coordinates by a clean linear rule
- You can express the transform as a composition of simpler reflections
Choose another pattern when
- Non-square matrix → can't rotate in place; allocate the rotated buffer
- Rotation by an arbitrary angle (not a multiple of 90°) → this is image processing, not this trick
- You're allowed O(n²) extra space and clarity matters more → just copy with the index map
- You need to rotate a *list* or *string*, not a grid → that's array reversal, not transpose
Interview takeaway
Any 90° rotation decomposes into a transpose plus a reflection. Once you see rotations as compositions of reflections, the whole family — rotate clockwise, counter-clockwise, 180°, flip diagonally — becomes the same two-line move with the reversal swapped around.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternCanonical In-Place Matrix Transform. Recognise it whenever a square grid must be rotated or reflected with O(1) extra space — decompose the transform into a transpose plus a reversal. Same coordinate-juggling family as Spiral Matrix, Set Matrix Zeroes, and Transpose Matrix.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Spiral MatrixAnother coordinate-walking matrix problem — boundary pointers instead of a reflection.
- Spiral Matrix IIComing soonFill an n×n matrix in spiral order — same boundary-shrinking simulation in reverse.
- Set Matrix ZeroesIn-place matrix mutation again — use the first row/col as flags for O(1) space.
- Transpose MatrixComing soonJust the first half of this problem — and it allows non-square input, so you can't do it fully in place.