Rotate a Square Matrix Clockwise While Both Diagonals Stay Fixed
Company: Sig
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Online Assessment
Rotate a square matrix clockwise by 90 degrees a given number of times, except that every element on either diagonal stays where it is.
The two diagonals split the remaining cells into four triangular regions (top, right, bottom, and left). One clockwise turn moves each non-diagonal element exactly as an ordinary 90-degree clockwise rotation of the whole matrix would: the top region moves into the right region, the right region into the bottom, the bottom into the left, and the left into the top. Elements on the main diagonal and on the anti-diagonal never move.
### Function Signature
`rotate_except_diagonals(matrix: list[list[int]], turns: int) -> list[list[int]]`
### Rules
- `matrix` is `n x n`. Cell `(r, c)` (zero-based row and column) is a diagonal cell when `r == c` or `r + c == n - 1`.
- One clockwise turn moves the value at every non-diagonal cell `(r, c)` to cell `(c, n - 1 - r)`. Every diagonal cell keeps its value.
- Apply exactly `turns` consecutive clockwise turns and return the resulting matrix as an `n x n` list of lists.
### Constraints
- `1 <= n <= 100`.
- `1 <= turns <= 4`.
- Every element is an integer in `[-1000000000, 1000000000]`.
### Examples
Input: `matrix = [[1,2,3,4,5],[2,1,9,6,3],[7,0,4,8,1],[5,2,4,1,9],[6,4,3,2,1]], turns = 1`
Output: `[[1,5,7,2,5],[4,1,0,6,2],[3,4,4,9,3],[2,2,8,1,4],[6,9,1,3,1]]`
The main-diagonal values 1, 1, 4, 1, 1 and the anti-diagonal values 5, 6, 4, 2, 6 stay in place. The non-diagonal values of the first column, 2, 7, 5 from top to bottom, move into the top row at columns 3, 2, and 1, so the top row becomes `1, 5, 7, 2, 5`.
Input: `matrix = [[1,2,3],[4,5,6],[7,8,9]], turns = 2`
Output: `[[1,8,3],[6,5,4],[7,2,9]]`
Input: `matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]], turns = 1`
Output: `[[1,9,5,4],[14,6,7,2],[15,10,11,3],[13,12,8,16]]`
With an even size the diagonals do not share a center cell: the eight diagonal values stay fixed and the other eight rotate.
Overview: Rotate every element of a square matrix that lies off both diagonals by 90 degrees clockwise a given number of times, leaving the main-diagonal and anti-diagonal values in place. It tests precise index mapping, handling of odd and even matrix sizes, and bug-free simulation under timed assessment conditions.
Read the full Sig Software Engineer interview experience this question came from
You are given a square matrix `matrix` of size `n x n` and an integer `turns`. Rotate the matrix clockwise by 90 degrees exactly `turns` times, with one exception: every element that lies on either diagonal stays exactly where it is.
A cell `(r, c)` (zero-based row `r`, zero-based column `c`) is a diagonal cell when `r == c` (main diagonal) or when `r + c == n - 1` (anti-diagonal). When `n` is odd the center cell belongs to both diagonals; when `n` is even the two diagonals share no cell.
One clockwise turn moves the value at every non-diagonal cell `(r, c)` to cell `(c, n - 1 - r)` — exactly where an ordinary 90-degree clockwise rotation of the whole matrix would place it. Every diagonal cell keeps its own value. Equivalently, the two diagonals cut the remaining cells into four triangular regions (top, right, bottom and left), and one turn moves the top region into the right region, the right into the bottom, the bottom into the left, and the left into the top.
Apply exactly `turns` consecutive clockwise turns and return the resulting matrix as an `n x n` list of lists.
Output semantics: the answer is the exact resulting grid, with rows in order from top to bottom and columns in order from left to right, so every input has exactly one correct output. Values are only relocated, never combined, so every element of the answer is one of the input elements and fits in a signed 32-bit integer (no value can exceed 2^31 - 1).
Example 1:
Input: `matrix = [[1,2,3,4,5],[2,1,9,6,3],[7,0,4,8,1],[5,2,4,1,9],[6,4,3,2,1]]`, `turns = 1`
Output: `[[1,5,7,2,5],[4,1,0,6,2],[3,4,4,9,3],[2,2,8,1,4],[6,9,1,3,1]]`
Explanation: the main-diagonal values 1, 1, 4, 1, 1 and the anti-diagonal values 5, 6, 4, 2, 6 stay in place. The non-diagonal values of the first column, 2, 7, 5 from top to bottom, move into the top row at columns 3, 2 and 1, so the top row becomes `1, 5, 7, 2, 5`.
Example 2:
Input: `matrix = [[1,2,3],[4,5,6],[7,8,9]]`, `turns = 2`
Output: `[[1,8,3],[6,5,4],[7,2,9]]`
Explanation: only 2, 4, 6 and 8 are non-diagonal. The first turn produces `[[1,4,3],[8,5,2],[7,6,9]]`, and the second turn produces `[[1,8,3],[6,5,4],[7,2,9]]`; 1, 5, 9, 3 and 7 never move.
Constraints
- matrix is n x n with 1 <= n <= 100.
- 1 <= turns <= 4.
- Every element is an integer in [-1000000000, 1000000000].
- Cell (r, c) uses zero-based row and column indices; it is a diagonal cell when r == c or r + c == n - 1.
- Values are only moved, never combined, so every result value fits in a signed 32-bit integer.
Examples
Input: ([[7]], 3)
Expected Output: [[7]]
Explanation: Minimum size n = 1: the only cell (0, 0) satisfies both r == c and r + c == n - 1, so it is pinned and the matrix is unchanged for any number of turns.
Input: ([[1, 2], [3, 4]], 1)
Expected Output: [[1, 2], [3, 4]]
Explanation: Degenerate n = 2: all four cells lie on a diagonal ((0,0) and (1,1) on the main, (0,1) and (1,0) on the anti), so nothing moves.
Hints
- Re-read the definition of a pinned cell: (r, c) is pinned when r == c or when r + c == n - 1, so for odd n the center cell belongs to both diagonals and must be treated as pinned exactly once.
- One turn sends the value at (r, c) to (c, n - 1 - r). Decide up front whether you are pushing values to their destinations or pulling values from their sources, and make sure a value you still need has not already been overwritten.
- turns is at most 4, and four clockwise turns bring every non-diagonal cell back to where it started — checking that turns = 4 reproduces the input is a cheap way to confirm your mapping is clockwise and not counter-clockwise or transposed.