Skip to main content

49. Spiral Matrix

mediumAsked at Salesforce

Return all elements of a matrix in spiral order. Salesforce uses this to test boundary tracking and clean iteration when corners get tricky.

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

Source citations

Public interview reports confirming this problem appears in Salesforce loops.

  • Glassdoor (2026-Q1)Salesforce uses this to test matrix-boundary off-by-one debugging.
  • Blind (2025)Common pairing with LC 48 (rotate image).

Problem

Given an m x n matrix, return all elements of the matrix in spiral order.

Constraints

  • m == matrix.length
  • n == matrix[i].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]

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 array with visited tracking

Move in directions right, down, left, up cyclically; mark visited cells.

Time
O(m*n)
Space
O(m*n)
function spiralOrder(matrix) {
  const m = matrix.length, n = matrix[0].length;
  const visited = Array.from({ length: m }, () => new Array(n).fill(false));
  const dirs = [[0,1],[1,0],[0,-1],[-1,0]];
  let d = 0, r = 0, c = 0;
  const result = [];
  for (let i = 0; i < m * n; i++) {
    result.push(matrix[r][c]);
    visited[r][c] = true;
    const nr = r + dirs[d][0], 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: Works but uses O(m*n) extra space.

2. Shrinking bounds

Maintain top/bottom/left/right boundaries. Walk one side, shrink the relevant boundary, rotate. Stop when bounds cross.

Time
O(m*n)
Space
O(1)
function spiralOrder(matrix) {
  const result = [];
  let top = 0, bottom = matrix.length - 1, 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: O(1) extra space. The if-guards on the third and fourth loops prevent double-counting on single-row or single-column residuals.

Salesforce-specific tips

Salesforce specifically grades on the if-guards in the third and fourth direction loops — without them, single-row residuals get duplicated. Bonus signal: explain WHEN the guard fires (when the matrix has shrunk to a single row or column).

Common mistakes

  • Forgetting the guards on the last two loops — duplicates elements on non-square matrices.
  • Not updating bounds AFTER the loop — wrong starting row/column.
  • Confusing m and n — matrix.length is rows (m), matrix[0].length is cols (n).

Follow-up questions

An interviewer at Salesforce may pivot to one of these next:

  • Spiral Matrix II (LC 59) — fill an n x n matrix in spiral order.
  • Spiral Matrix III (LC 885) — spiral with a starting point.
  • Diagonal Traverse (LC 498).

Solve it now

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

Output

Press Run or Cmd+Enter to execute

FAQ

Why the guards on the last two loops?

After walking right and down, top may exceed bottom (single row consumed). Walking left/up again would duplicate. The guards detect this and skip.

Could I do this recursively?

Yes — recurse on the inner sub-matrix after walking the outer ring. Iterative is more memory-efficient.

Practice these live with InterviewChamp.AI

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

Practice these live with InterviewChamp.AI →