Home / Patterns / Lesson 15

Matrix Patterns — Traversals, Rotation & In-Place Tricks

Medium ⏱ 5 min read 🧩 Pattern 15 of 16

2D-array problems look intimidating but reduce to a few reusable moves.

Move 1: rotate 90° = transpose + reverse rows

// Clockwise rotation, in place
function rotate(m) {
  const n = m.length;
  for (let r = 0; r < n; r++)              // transpose (flip across diagonal)
    for (let c = r + 1; c < n; c++)
      [m[r][c], m[c][r]] = [m[c][r], m[r][c]];
  for (const row of m) row.reverse();       // then mirror each row
  return m;
}

Nobody derives rotation index math under pressure — everyone who passes just knows this two-step decomposition. (Counter-clockwise: transpose, then reverse columns.)

Move 2: spiral order = four shrinking walls

let top = 0, bottom = rows - 1, left = 0, right = cols - 1;
while (top <= bottom && left <= right) {
  for (let c = left; c <= right; c++)  out.push(m[top][c]);      top++;
  for (let r = top; r <= bottom; r++)  out.push(m[r][right]);    right--;
  if (top <= bottom) { for (let c = right; c >= left; c--) out.push(m[bottom][c]); bottom--; }
  if (left <= right) { for (let r = bottom; r >= top; r--) out.push(m[r][left]);  left++;  }
}

Four boundaries that shrink inward. The two if guards prevent double-visiting on non-square matrices — the exact edge case interviewers test.

Move 3: use the matrix itself as storage

"Set entire row/column to zero if a cell is zero, in O(1) space" — use the first row and column as marker arrays instead of allocating new ones. This borrow-the-input trick recurs across in-place matrix problems (game of life uses spare bits similarly).

Spot it when…

  • Rotation/spiral/diagonal traversal — recall the template, don't derive.
  • "In place" + matrix → the first-row/column marker trick.
  • Islands/regions in a grid → that's DFS flood fill, not this.

Indexing sanity: m[row][col], rows first. Half of matrix bugs are r/c swaps — name your loop variables r and c, never i and j.