You're given an n×n grid of values — think of it as the pixels of a square image. Implement matrixRotation(matrix), which rotates the grid 90 degrees clockwise and returns the rotated grid as a new 2D array. This is the operation behind the "rotate" button in a photo app: every cell moves to where it would land if you turned the whole picture a quarter-turn to the right. The input must be left untouched.
// matrix: number[][] — a square (n×n) 2D array. Rows and columns are equal in length.
// returns: number[][] — a NEW n×n 2D array, rotated 90° clockwise.
// The input `matrix` is NOT modified.
function matrixRotation(matrix): number[][];
After a clockwise rotation, the cell at matrix[i][j] ends up at result[j][n-1-i]. Equivalently, the first row of the result is the first column of the input read bottom-to-top.
// 3×3 — the top row (1, 2, 3) becomes the right-hand column, top to bottom.
matrixRotation([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]);
// → [
// [7, 4, 1],
// [8, 5, 2],
// [9, 6, 3],
// ]
// 2×2 — the smallest non-trivial case.
matrixRotation([
[1, 2],
[3, 4],
]);
// → [
// [3, 1],
// [4, 2],
// ]
n×n. You don't need to handle rectangular (m×n, m ≠ n) matrices — a rectangular rotation would change the dimensions, which is out of scope here (see the solution's Going further).matrix must be exactly what they passed in. (True in-place O(1)-space rotation is a separate exercise — covered in Going further.)1×1 case returns a fresh array rather than the original reference.You'll turn a square grid a quarter-turn to the right, building the rotated grid as a brand-new 2D array and leaving the original untouched.
Picture a square photo on your phone. You tap "rotate right," and every pixel slides to a new spot: the top edge swings down the right side, the right edge swings down to the bottom, and so on. A matrix is just that photo as a grid of numbers. matrixRotation(matrix) does the same quarter-turn — it takes an n×n grid and returns a new n×n grid where each value has moved to where a clockwise rotation would carry it. The catch the interviewer is watching for: you must return a new array and leave the caller's matrix exactly as it was.
Where does a single cell go? Look at the value matrix[i][j] — row i, column j. After a clockwise turn, its row index and column index trade roles, and the column gets flipped. Concretely, matrix[i][j] lands at result[j][n-1-i]. The cleanest way to see this: the top row of the input becomes the right-hand column of the output, top-to-bottom. The second row becomes the second-from-right column. And so on.
That single fact — matrix[i][j] → result[j][n-1-i] — is enough to write a correct solution directly. We'll do exactly that first, then find a way to express the same move that's easier to remember and harder to get backwards.
If you trust the index formula, you can allocate a fresh n×n grid and copy every cell into its destination:
function matrixRotation(matrix) {
const n = matrix.length;
// Allocate an n×n grid of empty slots.
const rotated = Array.from({ length: n }, () => new Array(n));
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
rotated[j][n - 1 - i] = matrix[i][j];
}
}
return rotated;
}
This is correct — it passes every test. It allocates a new grid (so the input is never touched) and places each value at its rotated address. There's nothing wrong with shipping it. The only real weakness is the line rotated[j][n - 1 - i] = matrix[i][j]: under interview pressure, it is dangerously easy to write n - 1 - j instead of n - 1 - i, or to swap which side gets the flip — and every one of those typos produces a plausible-looking-but-wrong grid (a counter-clockwise turn, a mirror image, a transpose). The index arithmetic is a small landmine. Can we get the same result without ever writing n - 1 - i?
Yes — by splitting the rotation into two moves that are each individually obvious. Transpose, then reverse each row.
The transpose reflects the grid across its main diagonal: matrix[i][j] swaps with matrix[j][i], which turns every row into a column. That alone is not the rotation — it's a mirror. But if you then reverse each row (flip it left-to-right), the two operations compose into exactly one clockwise quarter-turn.
function matrixRotation(matrix) {
const n = matrix.length;
// Step 1: transpose into a NEW grid. transposed[i][j] reads matrix[j][i],
// so row i of the result is column i of the input. We never write into
// `matrix`, so the caller's input is left untouched.
const transposed = Array.from({ length: n }, (_, i) =>
Array.from({ length: n }, (_, j) => matrix[j][i]),
);
// Step 2: reverse each row left-to-right. `reverse()` mutates the array it's
// called on — but each `row` here is a fresh array we just built, NOT a row
// of the input, so mutating it is safe.
return transposed.map((row) => row.reverse());
}
module.exports = { matrixRotation };
Two things make this safer than the index-arithmetic version. First, there is no n - 1 - i to fumble — reverse() does the column-flip for you, and you can't get the direction of a row reverse backwards. Second, the non-mutation guarantee is easy to see: the transpose reads from matrix but writes into a freshly allocated transposed, and the reverse() only ever touches those fresh rows. The input is read-only throughout. (If you transposed in place and then reversed, you'd be mutating the caller's array — which this problem forbids. See Going further for that variant.)
A note on direction, because it's the easiest thing to get wrong: transpose then reverse each row gives a clockwise turn. Transpose then reverse each column (equivalently, reverse each row then transpose) gives a counter-clockwise turn. We want clockwise, so we reverse rows.
Let's rotate the 3×3 grid [[1,2,3],[4,5,6],[7,8,9]] end-to-end.
Step 1 — transpose. Row i of transposed is column i of the input:
input transposed (rows are the input's columns)
1 2 3 1 4 7 <- column 0 of input: 1, 4, 7
4 5 6 -> 2 5 8 <- column 1 of input: 2, 5, 8
7 8 9 3 6 9 <- column 2 of input: 3, 6, 9
The diagonal 1, 5, 9 stays fixed; every other cell crossed the diagonal to its mirror.
Step 2 — reverse each row. Flip each row of transposed left-to-right:
transposed reverse each row = rotated result
1 4 7 -> 7 4 1
2 5 8 -> 8 5 2
3 6 9 -> 9 6 3
Read the result against the mental-model picture: the input's top row 1, 2, 3 now sits in the right-hand column, top-to-bottom. That is the clockwise quarter-turn.
If you ever forget which order to do the two steps in, trace this 3×3 on paper — reversing rows before transposing produces a different (wrong) grid, and three rounds of pencil settle the order permanently.
[[1,2],[3,4]] must become [[3,1],[4,2]] for clockwise — and check against it.[[1,2],[3,4]] the transpose is [[1,3],[2,4]]; the rotation is [[3,1],[4,2]]. They differ — the transpose alone is never the answer. (One of the tests asserts exactly this.)Array.prototype.reverse() reverses in place and returns the same array. If you call .reverse() on a row of the original matrix, you've corrupted the caller's data. It's safe here only because every row we reverse is a fresh array produced by the transpose. If you build the result a different way, double-check that no method writes back into matrix.transposed.reverse()) instead of reversing within each row (row.reverse()). The first flips the grid top-to-bottom (giving a counter-clockwise turn); the second flips each row left-to-right (clockwise). They are not the same operation.n×n input, so reading n = matrix.length and indexing [0 .. n-1] in both dimensions is safe. On a genuinely rectangular m×n matrix the result would be n×m and you could not write it back into the same shape — see Going further.1×1 grid is its own rotation, but you must still return a new array, not the original reference. The transpose-then-map approach handles this for free: it allocates a fresh 1×1 grid and reverses a one-element row (a no-op). No special-casing needed.O(1) extra space. This problem asks for a new array, but the classic interview follow-up is to rotate the matrix in place — mutating the input and using no second grid. You process the matrix as concentric rings and rotate four cells at a time: top → right → bottom → left, using a single temporary. The outer loop walks the rings (layer from 0 to ⌊n/2⌋); the inner loop walks the cells along one side. Watch the index bookkeeping — it's the part everyone gets wrong. The picture below shows one four-way swap.matrix[i][j] ends up at result[n-1-i][n-1-j]. No transpose needed for the half-turn.m×n) rotation. When the matrix isn't square, a 90° rotation changes the dimensions: an m×n grid becomes n×m. You can't write the result back into the input's shape, so an in-place version is impossible — you must allocate a new n×m grid. The transpose-then-reverse idea still works (transpose of an m×n is n×m), you just size the output grid accordingly.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.
You're given an n×n grid of values — think of it as the pixels of a square image. Implement matrixRotation(matrix), which rotates the grid 90 degrees clockwise and returns the rotated grid as a new 2D array. This is the operation behind the "rotate" button in a photo app: every cell moves to where it would land if you turned the whole picture a quarter-turn to the right. The input must be left untouched.
// matrix: number[][] — a square (n×n) 2D array. Rows and columns are equal in length.
// returns: number[][] — a NEW n×n 2D array, rotated 90° clockwise.
// The input `matrix` is NOT modified.
function matrixRotation(matrix): number[][];
After a clockwise rotation, the cell at matrix[i][j] ends up at result[j][n-1-i]. Equivalently, the first row of the result is the first column of the input read bottom-to-top.
// 3×3 — the top row (1, 2, 3) becomes the right-hand column, top to bottom.
matrixRotation([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]);
// → [
// [7, 4, 1],
// [8, 5, 2],
// [9, 6, 3],
// ]
// 2×2 — the smallest non-trivial case.
matrixRotation([
[1, 2],
[3, 4],
]);
// → [
// [3, 1],
// [4, 2],
// ]
n×n. You don't need to handle rectangular (m×n, m ≠ n) matrices — a rectangular rotation would change the dimensions, which is out of scope here (see the solution's Going further).matrix must be exactly what they passed in. (True in-place O(1)-space rotation is a separate exercise — covered in Going further.)1×1 case returns a fresh array rather than the original reference.You'll turn a square grid a quarter-turn to the right, building the rotated grid as a brand-new 2D array and leaving the original untouched.
Picture a square photo on your phone. You tap "rotate right," and every pixel slides to a new spot: the top edge swings down the right side, the right edge swings down to the bottom, and so on. A matrix is just that photo as a grid of numbers. matrixRotation(matrix) does the same quarter-turn — it takes an n×n grid and returns a new n×n grid where each value has moved to where a clockwise rotation would carry it. The catch the interviewer is watching for: you must return a new array and leave the caller's matrix exactly as it was.
Where does a single cell go? Look at the value matrix[i][j] — row i, column j. After a clockwise turn, its row index and column index trade roles, and the column gets flipped. Concretely, matrix[i][j] lands at result[j][n-1-i]. The cleanest way to see this: the top row of the input becomes the right-hand column of the output, top-to-bottom. The second row becomes the second-from-right column. And so on.
That single fact — matrix[i][j] → result[j][n-1-i] — is enough to write a correct solution directly. We'll do exactly that first, then find a way to express the same move that's easier to remember and harder to get backwards.
If you trust the index formula, you can allocate a fresh n×n grid and copy every cell into its destination:
function matrixRotation(matrix) {
const n = matrix.length;
// Allocate an n×n grid of empty slots.
const rotated = Array.from({ length: n }, () => new Array(n));
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
rotated[j][n - 1 - i] = matrix[i][j];
}
}
return rotated;
}
This is correct — it passes every test. It allocates a new grid (so the input is never touched) and places each value at its rotated address. There's nothing wrong with shipping it. The only real weakness is the line rotated[j][n - 1 - i] = matrix[i][j]: under interview pressure, it is dangerously easy to write n - 1 - j instead of n - 1 - i, or to swap which side gets the flip — and every one of those typos produces a plausible-looking-but-wrong grid (a counter-clockwise turn, a mirror image, a transpose). The index arithmetic is a small landmine. Can we get the same result without ever writing n - 1 - i?
Yes — by splitting the rotation into two moves that are each individually obvious. Transpose, then reverse each row.
The transpose reflects the grid across its main diagonal: matrix[i][j] swaps with matrix[j][i], which turns every row into a column. That alone is not the rotation — it's a mirror. But if you then reverse each row (flip it left-to-right), the two operations compose into exactly one clockwise quarter-turn.
function matrixRotation(matrix) {
const n = matrix.length;
// Step 1: transpose into a NEW grid. transposed[i][j] reads matrix[j][i],
// so row i of the result is column i of the input. We never write into
// `matrix`, so the caller's input is left untouched.
const transposed = Array.from({ length: n }, (_, i) =>
Array.from({ length: n }, (_, j) => matrix[j][i]),
);
// Step 2: reverse each row left-to-right. `reverse()` mutates the array it's
// called on — but each `row` here is a fresh array we just built, NOT a row
// of the input, so mutating it is safe.
return transposed.map((row) => row.reverse());
}
module.exports = { matrixRotation };
Two things make this safer than the index-arithmetic version. First, there is no n - 1 - i to fumble — reverse() does the column-flip for you, and you can't get the direction of a row reverse backwards. Second, the non-mutation guarantee is easy to see: the transpose reads from matrix but writes into a freshly allocated transposed, and the reverse() only ever touches those fresh rows. The input is read-only throughout. (If you transposed in place and then reversed, you'd be mutating the caller's array — which this problem forbids. See Going further for that variant.)
A note on direction, because it's the easiest thing to get wrong: transpose then reverse each row gives a clockwise turn. Transpose then reverse each column (equivalently, reverse each row then transpose) gives a counter-clockwise turn. We want clockwise, so we reverse rows.
Let's rotate the 3×3 grid [[1,2,3],[4,5,6],[7,8,9]] end-to-end.
Step 1 — transpose. Row i of transposed is column i of the input:
input transposed (rows are the input's columns)
1 2 3 1 4 7 <- column 0 of input: 1, 4, 7
4 5 6 -> 2 5 8 <- column 1 of input: 2, 5, 8
7 8 9 3 6 9 <- column 2 of input: 3, 6, 9
The diagonal 1, 5, 9 stays fixed; every other cell crossed the diagonal to its mirror.
Step 2 — reverse each row. Flip each row of transposed left-to-right:
transposed reverse each row = rotated result
1 4 7 -> 7 4 1
2 5 8 -> 8 5 2
3 6 9 -> 9 6 3
Read the result against the mental-model picture: the input's top row 1, 2, 3 now sits in the right-hand column, top-to-bottom. That is the clockwise quarter-turn.
If you ever forget which order to do the two steps in, trace this 3×3 on paper — reversing rows before transposing produces a different (wrong) grid, and three rounds of pencil settle the order permanently.
[[1,2],[3,4]] must become [[3,1],[4,2]] for clockwise — and check against it.[[1,2],[3,4]] the transpose is [[1,3],[2,4]]; the rotation is [[3,1],[4,2]]. They differ — the transpose alone is never the answer. (One of the tests asserts exactly this.)Array.prototype.reverse() reverses in place and returns the same array. If you call .reverse() on a row of the original matrix, you've corrupted the caller's data. It's safe here only because every row we reverse is a fresh array produced by the transpose. If you build the result a different way, double-check that no method writes back into matrix.transposed.reverse()) instead of reversing within each row (row.reverse()). The first flips the grid top-to-bottom (giving a counter-clockwise turn); the second flips each row left-to-right (clockwise). They are not the same operation.n×n input, so reading n = matrix.length and indexing [0 .. n-1] in both dimensions is safe. On a genuinely rectangular m×n matrix the result would be n×m and you could not write it back into the same shape — see Going further.1×1 grid is its own rotation, but you must still return a new array, not the original reference. The transpose-then-map approach handles this for free: it allocates a fresh 1×1 grid and reverses a one-element row (a no-op). No special-casing needed.O(1) extra space. This problem asks for a new array, but the classic interview follow-up is to rotate the matrix in place — mutating the input and using no second grid. You process the matrix as concentric rings and rotate four cells at a time: top → right → bottom → left, using a single temporary. The outer loop walks the rings (layer from 0 to ⌊n/2⌋); the inner loop walks the cells along one side. Watch the index bookkeeping — it's the part everyone gets wrong. The picture below shows one four-way swap.matrix[i][j] ends up at result[n-1-i][n-1-j]. No transpose needed for the half-turn.m×n) rotation. When the matrix isn't square, a 90° rotation changes the dimensions: an m×n grid becomes n×m. You can't write the result back into the input's shape, so an in-place version is impossible — you must allocate a new n×m grid. The transpose-then-reverse idea still works (transpose of an m×n is n×m), you just size the output grid accordingly.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.