Algorithm

Spiral Matrix

Arrays & Strings Pattern

Spiral Matrix

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
EXAMPLE 1
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,2,3,6,9,8,7,4,5]
Full perimeter clockwise, then the single center cell.
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]
Rectangular 3×4: after the outer loop, the surviving region is the single middle row [6, 7], read left to right.
EXAMPLE 3
Input: matrix = [[7],[9],[6]]
Output: [7,9,6]
A single column: the top edge takes 7, the right edge walks down through 9 and 6. The guards prevent walking back up.
Can the matrix be rectangular, not square?
Yes — m and n can differ, and that is where solutions break. The inner layers can degenerate into a single row or column, so the completion check after every edge (not just per loop) is what prevents duplicate visits.
Is a single row or single column valid input?
Yes. A 1×n matrix is just its row left to right; an m×1 matrix is its column top to bottom. Both fall out of the fence logic with the guards in place.
Should I return the elements or print them?
Return them as a flat list of m×n values in visiting order.

Traversing a matrix in spiral order means visiting every element in a clockwise, inward-spiraling path. The challenge is ensuring we visit every cell exactly once and knowing exactly when to turn to stay within the unvisited boundaries.

1. The Strategy: Direction Vectors (O(M*N) space)

One way to spiral is to maintain a current direction (Right, Down, Left, Up) and a set to keep track of already visited cells. We move until we hit a wall or a visited cell, then turn 90 degrees.

python
res = []
visited = set()
r, c = 0, 0
dr, dc = [0, 1, 0, -1], [1, 0, -1, 0] # Right, Down, Left, Up
di = 0 # Current direction index
for _ in range(rows * cols):
    res.append(matrix[r][c])
    visited.add((r, c))
    nr, nc = r + dr[di], c + dc[di]
    if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in visited:
        r, c = nr, nc
    else:
        di = (di + 1) % 4
        r, c = r + dr[di], c + dc[di]
return res
2. The Insight: Boundary Contraction

Using a "visited" set or grid takes O(M*N) extra space. The core insight is that as we complete each edge of the spiral, that entire row or column is used up. We can simply shrink the boundaries of the grid inward after every turn, removing the need for a visited set.

3. The Optimal Strategy: Shrinking Fences (O(M*N))

We maintain four pointers: top, bottom, left, and right, representing the fences of our active grid.
- Go Right: Along top row. When done, increment top (row is consumed).
- Go Down: Along right column. When done, decrement right.
- Go Left: Along bottom row (if still valid). When done, decrement bottom.
- Go Up: Along left column (if still valid). When done, increment left.
This repeats until the fences cross.

python
m, n = len(matrix), len(matrix[0])
top, bottom = 0, m - 1
left, right = 0, n - 1
res = []

while len(res) < m * n:
    # 1. Right
    for j in range(left, right + 1): res.append(matrix[top][j])
    top += 1
    
    # 2. Down
    for i in range(top, bottom + 1): res.append(matrix[i][right])
    right -= 1
    
    # 3. Left
    if top <= bottom:
        for j in range(right, left - 1, -1): res.append(matrix[bottom][j])
        bottom -= 1
        
    # 4. Up
    if left <= right:
        for i in range(bottom, top - 1, -1): res.append(matrix[i][left])
        left += 1
return res
Worked Example:3x3 Grid
11
22
33
4
5
6
7
8
9
We traverse the top boundary from left to right, visiting 1, 2, and 3. When we reach the corner, we shift the top boundary down by one row.
11
22
33
4
5
64
7
8
95
We traverse the right boundary from top to bottom, visiting 6 and 9. When we reach the bottom corner, we shift the right boundary left by one column.
11
22
33
4
5
64
77
86
95
We traverse the bottom boundary from right to left, visiting 8 and 7. When we reach the corner, we shift the bottom boundary up by one row.
11
22
33
48
59
64
77
86
95
We traverse the left boundary upward to visit 4, then move inward to collect the final central element 5, completing our spiral path.
Interactive Strategy Visualization

Spiral Traversal

Boundary-Based Navigation
1
2
3
4
5
6
7
8
9

Starting at [0,0]. Moving Right along the Top Wall.

O(M×N) + Visited Set
O(M×N) + O(1) Shrinking Fences