← All Problems

33. Rotate Dashboard Matrix

General Pattern Medium Matrix In-Place
Grounding: Note: general algorithmic pattern relevant to conversational-AI/support-ops engineering; not a confirmed detail of Fin's specific implementation.

Problem

An ops dashboard lays out N metrics widgets in an N x N grid. When the UI orientation changes, the entire layout needs to rotate 90 degrees clockwise, without allocating a second full matrix, since the grid can be large and this runs on every orientation change.

The function mutates matrix in place (e.g. transpose then reverse each row, or layer-by-layer rotation), using O(1) extra space (aside from the input itself) and O(n²) time. It returns nothing; the caller inspects the mutated matrix.

Source: src/33_rotate_dashboard_matrix.py

def rotate(matrix: list[list[int]]) -> None:

>>> m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> rotate(m)
>>> m
[[7, 4, 1], [8, 5, 2], [9, 6, 3]]

Step-by-Step Approach

  1. Recognize that a 90-degree clockwise rotation can be decomposed into two simpler, well-known in-place operations: transpose, then reverse each row.
  2. Transpose the matrix in place by swapping matrix[i][j] with matrix[j][i] for every pair where j > i (only the upper triangle, to avoid swapping each pair back).
  3. After the transpose, each row of the matrix currently holds what will become that row of the rotated matrix, but in reverse column order.
  4. Reverse each row in place (row.reverse()) to finish the rotation.
  5. Handle the trivial cases (empty matrix, 1x1 matrix) — they fall out naturally since the loops simply don't execute.

The key insight is that "rotate 90° clockwise" decomposes into "transpose" (reflect across the main diagonal) followed by "reverse each row" (reflect across the vertical axis) — two reflections compose into the rotation, and both are doable in place with only pairwise swaps.

Reference solution

def rotate(matrix: list[list[int]]) -> None:
    # transpose in place, then reverse each row, O(n^2) time, O(1) extra space
    n = len(matrix)
    for i in range(n):
        # upper triangle only, avoids swapping back
        for j in range(i + 1, n):
            # tuple-swap, no temp var
            matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
    for row in matrix:
        # flips column order to finish the rotation
        row.reverse()

Key Functions & Tricks

  • a, b = b, a — Python's tuple-swap idiom, no temp variable needed.
  • range(i + 1, n) for the inner loop — upper-triangle-only swap so each pair swaps exactly once.
  • list.reverse() — reverses a list in place, returns None.
  • Transpose + row-reverse — two reflections that compose into a 90° clockwise rotation, O(n²) time, O(1) space.

How to Recognize This Pattern

Signals: "rotate a square matrix in place," "no extra matrix allowed," "O(1) extra space." Any time an interviewer specifically forbids allocating a new grid, they're pointing you at the transpose-then-reverse (or layer-by-layer four-way swap) technique rather than the naive "build a new rotated matrix and copy it back" approach. Variations: (1) rotate counter-clockwise instead — reverse each row before transposing, or transpose then reverse columns instead of rows; (2) rotate by an arbitrary multiple of 90° — reduce k % 4 and repeat, or handle 180°/270° with direct index math. A common pitfall is transposing over the full matrix instead of just the upper triangle (j > i), which swaps every pair twice and silently undoes the transpose.