54. Spiral Matrix
mediumAsked at JPMorganReturn all elements of a matrix in spiral order. JPMorgan asks this on SDE onsites to test whether you can manage four moving boundaries (top, bottom, left, right) without falling into the off-by-one trap that hits 80% of candidates.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in JPMorgan loops.
- Glassdoor (2026-Q1)— Recurring JPMorgan SDE onsite matrix problem in 2026-Q1 reviews.
- LeetCode (2026-Q1)— Tagged JPMorgan on the LeetCode company tag page.
- Reddit r/cscareerquestions (2025-12)— JPMC SWE-II write-up: 'spiral matrix on the onsite — they specifically watched for off-by-one bugs'.
Problem
Given an m x n matrix, return all elements of the matrix in spiral order.
Constraints
m == matrix.lengthn == matrix[i].length1 <= m, n <= 10-100 <= matrix[i][j] <= 100
Examples
Example 1
matrix = [[1,2,3],[4,5,6],[7,8,9]][1,2,3,6,9,8,7,4,5]Example 2
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]][1,2,3,4,8,12,11,10,9,5,6,7]Approaches
1. Four moving boundaries (optimal)
Maintain top, bottom, left, right. Walk right along top, down along right, left along bottom (if rows remain), up along left (if cols remain). Shrink the boundary after each side.
- Time
- O(m * n)
- Space
- O(1) extra (output not counted)
function spiralOrder(matrix) {
const out = [];
let top = 0;
let bottom = matrix.length - 1;
let left = 0;
let right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (let j = left; j <= right; j++) out.push(matrix[top][j]);
top++;
for (let i = top; i <= bottom; i++) out.push(matrix[i][right]);
right--;
if (top <= bottom) {
for (let j = right; j >= left; j--) out.push(matrix[bottom][j]);
bottom--;
}
if (left <= right) {
for (let i = bottom; i >= top; i--) out.push(matrix[i][left]);
left++;
}
}
return out;
}Tradeoff: O(m * n) time with O(1) extra space — the canonical answer. The two if-guards before the bottom row and left column are what handle non-square matrices (where the inner loop can leave one side already exhausted).
2. Direction array with seen-grid
Walk one cell at a time. Try the current direction; if out-of-bounds or already-seen, turn right.
- Time
- O(m * n)
- Space
- O(m * n) for the seen grid
function spiralOrderDir(matrix) {
const m = matrix.length;
const n = matrix[0].length;
const seen = Array.from({ length: m }, () => new Array(n).fill(false));
const dr = [0, 1, 0, -1];
const dc = [1, 0, -1, 0];
let r = 0, c = 0, di = 0;
const out = [];
for (let i = 0; i < m * n; i++) {
out.push(matrix[r][c]);
seen[r][c] = true;
const nr = r + dr[di];
const nc = c + dc[di];
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !seen[nr][nc]) {
r = nr; c = nc;
} else {
di = (di + 1) % 4;
r += dr[di];
c += dc[di];
}
}
return out;
}Tradeoff: Conceptually cleaner — one cell at a time — but uses O(m * n) extra memory for the visited grid. JPMorgan interviewers accept both, but the boundary version is the canonical answer.
JPMorgan-specific tips
JPMorgan interviewers focus on the two non-square guards in the boundary approach. The interviewer runs your code on a 1xN or Mx1 matrix; without the guards, you double-traverse the single row/column. State explicitly: 'after the right-then-down sweep, I check whether there are still rows below top — if not, skip the bottom row.' Many candidates write the four loops and miss the guards.
Common mistakes
- Omitting the 'if (top <= bottom)' guard before the bottom row — double-traverses on single-row matrices.
- Off-by-one on the four for-loops — easiest case: the right boundary, must iterate from top (the now-decremented value) to bottom.
- Trying to compute the spiral with a closed-form indexing scheme — too brittle.
- Mutating the input matrix (setting visited cells to a sentinel) — works but harms the caller.
Follow-up questions
An interviewer at JPMorgan may pivot to one of these next:
- Spiral Matrix II (LC 59) — fill an n x n matrix with 1..n^2 in spiral order.
- Spiral Matrix III (LC 885) — start at an arbitrary cell, walk outwards in a spiral until you cover an R x C bounding box.
- Diagonal traverse (LC 498).
- What if you must spiral over a sparse matrix (mostly zeros)?
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Why do you need the two inner if-guards in the boundary approach?
After top has been incremented and right decremented, the third leg (right-to-left along bottom) is only valid if rows still remain (top <= bottom). Same for the fourth leg (bottom-to-top along left, requires left <= right). On a 1xN or Mx1 matrix the first two legs already cover every cell, and the guards prevent re-traversing them.
Which approach is preferred?
Boundary approach for the canonical answer — O(1) extra space and the explicit boundaries map directly to your verbal explanation. Direction-array version when the interviewer asks 'what if the matrix had irregular obstacles' — that variant generalises more cleanly.
Free learning resources
Curated free links for this problem.
Practice these live with InterviewChamp.AI
Drill Spiral Matrix and other JPMorgan interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →