MediumMatrix Simulation

Spiral Matrix โ€” Solution

Problem

Given an m ร— n grid of integers, return all of its values in spiral order โ€” starting from the top-left corner, sweeping right, then down, then left, then up, and repeating inward until every cell is visited.

Example:

  • Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
  • Output: [1, 2, 3, 6, 9, 8, 7, 4, 5]
  • Explanation: Sweep right across row 0, down column 2, left across row 2, up column 0, then the center cell.

A 1ร—1 matrix [[42]] returns [42] โ€” the loop handles this without any special case.

Intuition

A spiral follows a repeating four-step rhythm: right โ†’ down โ†’ left โ†’ up. After completing each edge, that row or column is "used up" and the active region shrinks by one layer. Tracking four boundary pointers and shrinking them immediately after each pass lets you traverse every cell exactly once without any visited bookkeeping.

Approach 1 โ€” Direction Rotation

Simulate the spiral by cycling through four direction vectors. Move in the current direction until the next step would exit the grid or revisit a cell, then rotate 90ยฐ clockwise.

Steps:

  1. Define four direction vectors: right, down, left, up
  2. Allocate a visited boolean grid the same size as matrix
  3. For each of the m ร— n elements, append the current cell and mark it visited
  4. Compute the next cell in the current direction
  5. If next cell is out of bounds or visited, rotate to the next direction before moving
1def spiralOrder(matrix):
2    rows, cols = len(matrix), len(matrix[0])
3    visited = [[False] * cols for _ in range(rows)]
4    directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]  # right, down, left, up
5    dir_index = 0
6    row, col = 0, 0
7    result = []
8
9    for _ in range(rows * cols):
10        result.append(matrix[row][col])
11        visited[row][col] = True
12
13        next_row = row + directions[dir_index][0]
14        next_col = col + directions[dir_index][1]
15
16        # Rotate direction if next cell is out of bounds or already visited
17        if (next_row < 0 or next_row >= rows or
18                next_col < 0 or next_col >= cols or
19                visited[next_row][next_col]):
20            dir_index = (dir_index + 1) % 4
21            next_row = row + directions[dir_index][0]
22            next_col = col + directions[dir_index][1]
23
24        row, col = next_row, next_col
25
26    return result
  • Time: O(m ร— n) โ€” every cell is visited exactly once
  • Space: O(m ร— n) โ€” the visited grid mirrors the input dimensions

Approach 2 โ€” Boundary Simulation (Optimal)

Track four boundary pointers (top, bottom, left, right) defining the unvisited region. Walk each edge in spiral order, then immediately shrink the corresponding boundary. No visited array needed.

Steps:

  1. Initialize top = 0, bottom = rows - 1, left = 0, right = cols - 1
  2. Sweep left-to-right along the top row; increment top
  3. Sweep top-to-bottom along the right column; decrement right
  4. If rows remain (top <= bottom), sweep right-to-left along the bottom row; decrement bottom
  5. If columns remain (left <= right), sweep bottom-to-top along the left column; increment left
  6. Repeat until top > bottom or left > right
1def spiralOrder(matrix):
2    result = []
3    top, bottom = 0, len(matrix) - 1
4    left, right = 0, len(matrix[0]) - 1
5
6    while top <= bottom and left <= right:
7        for col in range(left, right + 1):
8            result.append(matrix[top][col])
9        top += 1  # shrink before the downward pass so the top-right corner isn't revisited
10
11        for row in range(top, bottom + 1):
12            result.append(matrix[row][right])
13        right -= 1
14
15        if top <= bottom:  # guard: a single remaining row has no reverse pass
16            for col in range(right, left - 1, -1):
17                result.append(matrix[bottom][col])
18            bottom -= 1
19
20        if left <= right:  # guard: a single remaining column has no upward pass
21            for row in range(bottom, top - 1, -1):
22                result.append(matrix[row][left])
23            left += 1
24
25    return result
  • Time: O(m ร— n) โ€” every cell is visited exactly once
  • Space: O(1) extra โ€” only four integer boundary variables beyond the output array

Complexity Summary

ApproachTimeSpaceWhen to use
Direction RotationO(m ร— n)O(m ร— n)When the visited-flag logic feels more natural and memory isn't constrained
Boundary SimulationO(m ร— n)O(1)Default choice โ€” identical speed, no extra memory

Common Mistakes

  • Missing the top <= bottom guard before the reverse bottom-row pass: When one row remains after the rightward sweep, omitting this check causes the same cells to be swept again right-to-left. A single-row matrix [[1,2,3]] produces [1,2,3,3,2,1] without this guard.
  • Missing the left <= right guard before the upward left-column pass: Same issue with a single remaining column โ€” the upward pass re-visits every cell just added by the downward pass.
  • Not incrementing top before the downward pass: The boundary must be shrunk immediately after each side is consumed. If top is still at the old value when the rightward column pass starts, matrix[top][right] (the top-right corner) is added twice.
  • Sweeping the bottom row left-to-right instead of right-to-left: The spiral direction is โ†’ โ†“ โ† โ†‘; reversing the bottom-row direction produces a rotation of the correct answer, not a spiral.
  • Assuming the matrix is square: Using a single n for both dimensions silently produces incorrect boundaries on any rectangular input like [[1,2,3],[4,5,6]].

Related Problems

  • rotate-image โ€” in-place 90ยฐ rotation uses the same layer-by-layer boundary thinking
  • set-matrix-zeroes โ€” in-place matrix modification that requires careful traversal to avoid corrupting later reads
  • search-a-2d-matrix โ€” exploits 2D grid structure with coordinate arithmetic instead of full traversal
  • game-of-life โ€” grid simulation where update rules depend on traversal order, similar to spiral's direction discipline
  • valid-sudoku โ€” structured traversal of fixed-size regions within a 2D grid

Ready to practice? Try it on SkillFlow

Adaptive problems, AI follow-up interviews, and a skill score that shows exactly where you need to improve.

Practice This Problem โ†’