Spiral Matrix
Given an m x n matrix, return all elements of the matrix in spiral order.
- m == matrix.length
- n == matrix[i].length
- 1 <= m, n <= 10
- -100 <= matrix[i][j] <= 100
matrix = [[1,2,3],[4,5,6],[7,8,9]][1,2,3,6,9,8,7,4,5]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]matrix = [[7],[9],[6]][7,9,6]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.
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.
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 resUsing 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.
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.
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 resSpiral Traversal
Starting at [0,0]. Moving Right along the Top Wall.
Shrinking Bounds
We track four walls: top, bottom, left, and right. Every time we finish traversing a wall, we shrink it inward, ensuring we never visit the same cell twice.
Edge Cases
Crucial: After moving left or up, check if the boundaries have crossed (top <= bottom) to avoid double-processing elements in non-square matrices.