Skip to main content

54. Spiral Matrix

mediumAsked at Canva

Traverse an m×n matrix in spiral order and return every element — Canva asks this to probe boundary-management discipline, the same discipline needed to correctly clip rendering passes to the visible canvas viewport.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Problem

Given an m×n matrix, return all elements in spiral order starting from the top-left corner, moving right, down, left, then up, shrinking the boundaries after each full sweep.

Constraints

  • m == matrix.length
  • n == matrix[0].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

Examples

Example 1

Input
matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output
[1,2,3,6,9,8,7,4,5]

Explanation: Right along row 0, down column 2, left along row 2, up column 0, then center.

Example 2

Input
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
Output
[1,2,3,4,8,12,11,10,9,5,6,7]

Approaches

1. Direction simulation

Walk the matrix following a right→down→left→up direction cycle, flipping direction when a boundary or visited cell is hit.

Time
O(m*n)
Space
O(m*n)
function spiralOrder(matrix) {
  const result = [];
  const m = matrix.length;
  const n = matrix[0].length;
  const visited = Array.from({ length: m }, () => Array(n).fill(false));
  const dirs = [[0,1],[1,0],[0,-1],[-1,0]];
  let r = 0, c = 0, d = 0;
  for (let i = 0; i < m * n; i++) {
    result.push(matrix[r][c]);
    visited[r][c] = true;
    const nr = r + dirs[d][0];
    const nc = c + dirs[d][1];
    if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc]) {
      d = (d + 1) % 4;
    }
    r += dirs[d][0];
    c += dirs[d][1];
  }
  return result;
}

Tradeoff:

2. Optimal (shrinking boundaries)

Maintain four boundary pointers (top, bottom, left, right) and peel one layer at a time, shrinking after each sweep — no visited array needed.

Time
O(m*n)
Space
O(1)
function spiralOrder(matrix) {
  const result = [];
  let top = 0, bottom = matrix.length - 1;
  let left = 0, right = matrix[0].length - 1;
  while (top <= bottom && left <= right) {
    for (let c = left; c <= right; c++) result.push(matrix[top][c]);
    top++;
    for (let r = top; r <= bottom; r++) result.push(matrix[r][right]);
    right--;
    if (top <= bottom) {
      for (let c = right; c >= left; c--) result.push(matrix[bottom][c]);
      bottom--;
    }
    if (left <= right) {
      for (let r = bottom; r >= top; r--) result.push(matrix[r][left]);
      left++;
    }
  }
  return result;
}

Tradeoff:

Canva-specific tips

Canva interviewers pay close attention to how you handle the asymmetric m×n case — a 1×n or m×1 matrix breaks naïve solutions that assume the inner guard conditions are symmetric. The shrinking-boundary approach is preferred: state your four pointers up front, trace through the 3×3 example to confirm you get 9 elements, then write the code. The guard conditions `if (top <= bottom)` and `if (left <= right)` before the third and fourth sweeps are the common failure point — explain why they're needed before you write them.

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

Practice these live with InterviewChamp.AI

Drill Spiral Matrix and other Canva interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →