Given an m x n matrix of integers matrix, return a list of all elements within the matrix in spiral order.
Example 1:
Input: matrix = [[1,2],[3,4]]
Output: [1,2,4,3]Example 2:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [1,2,3,6,9,8,7,4,5]Example 3:
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]Constraints:
1 <= matrix.length, matrix[i].length <= 10-100 <= matrix[i][j] <= 100
You should aim for a solution with O(m*n) time and O(1) extra space, where m is the number of rows and n is the number of columns in the given matrix.
Try to simulate the process as described in the problem. Think in terms of matrix layers, starting from the outermost boundaries and moving inward. Can you determine an efficient way to implement this?
Each boundary consists of four parts: the top row, right column, bottom row, and left column, which follow the spiral order and act as four pointers. For each layer, the top pointer increments by one, the right pointer decrements by one, the left pointer increments by one, and the bottom pointer decrements by one.
At each layer, four loops traverse the matrix: one moves left to right along the top row, another moves top to bottom along the right column, the next moves right to left along the bottom row, and the last moves bottom to top along the left column. This process generates the spiral order.
Before attempting this problem, you should be comfortable with:
We want to print the matrix in spiral order (right → down → left → up, repeating).
This solution treats the spiral as a sequence of smaller and smaller “rings”.
Each ring can be described by:
(r, c)(dr, dc) that tells us where to move nextAt each step, we do two things:
After moving along one edge, the remaining unvisited area becomes a smaller rectangle, and the next direction is obtained by “turning right” (changing (dr, dc)).
res.row = remaining rows to processcol = remaining columns to process(r, c)(dr, dc)row == 0 or col == 0, stop (nothing left to traverse)col steps in the current direction:(r, c) by (dr, dc)matrix[r][c] to resrow and col (because after turning, width/height swap)1 (one side was fully consumed)(0, -1) with direction (0, 1)res.class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m, n = len(matrix), len(matrix[0])
res = []
# append all the elements in the given direction
def dfs(row, col, r, c, dr, dc):
if row == 0 or col == 0:
return
for i in range(col):
r += dr
c += dc
res.append(matrix[r][c])
# sub-problem
dfs(col, row - 1, r, c, dc, -dr)
# start by going to the right
dfs(m, n, 0, -1, 0, 1)
return resWhere is the number of rows and is the number of columns.
We want to traverse a matrix in spiral order:
right → down → left → up, repeatedly, moving inward layer by layer.
A clean iterative way to do this is to maintain four boundaries:
top → the topmost unvisited rowbottom → one past the bottommost unvisited rowleft → the leftmost unvisited columnright → one past the rightmost unvisited columnAt each step, we walk along the current outer boundary in four directions:
After each pass, we shrink the boundaries inward.
res as an empty listleft = 0, right = number of columnstop = 0, bottom = number of rowsleft < right and top < bottom):left to right - 1 and append elements.toptop to bottom - 1 and append elements.rightright - 1 down to left and append elements.bottombottom - 1 up to top and append elements.leftres.class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
res = []
left, right = 0, len(matrix[0])
top, bottom = 0, len(matrix)
while left < right and top < bottom:
for i in range(left, right):
res.append(matrix[top][i])
top += 1
for i in range(top, bottom):
res.append(matrix[i][right - 1])
right -= 1
if not (left < right and top < bottom):
break
for i in range(right - 1, left - 1, -1):
res.append(matrix[bottom - 1][i])
bottom -= 1
for i in range(bottom - 1, top - 1, -1):
res.append(matrix[i][left])
left += 1
return resWhere is the number of rows and is the number of columns.
We want to read the matrix in spiral order: right → down → left → up, repeating.
Instead of keeping four boundaries (top, bottom, left, right), this approach tracks:
Key idea:
cols stepsrows - 1 stepscols - 1 stepsrows - 2 stepsWe store the remaining step counts in an array:
steps[0] = how many moves left in the horizontal directionsteps[1] = how many moves left in the vertical directiond & 1 tells us whether the current direction is horizontal (0) or vertical (1).
(0, 1), down (1, 0), left (0, -1), up (-1, 0)steps[0] = number of columnssteps[1] = number of rows - 1(r, c) = (0, -1) so the first move goes into (0, 0).d = 0 (start moving right).steps[d & 1] is greater than 0:steps[d & 1] times in direction d:(r, c) by the direction vectormatrix[r][c] to the resultsteps[d & 1] -= 1d = (d + 1) % 4class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
res = []
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
steps = [len(matrix[0]), len(matrix) - 1]
r, c, d = 0, -1, 0
while steps[d & 1]:
for i in range(steps[d & 1]):
r += directions[d][0]
c += directions[d][1]
res.append(matrix[r][c])
steps[d & 1] -= 1
d += 1
d %= 4
return resWhere is the number of rows and is the number of columns.
After completing a horizontal traversal, the vertical bounds may have crossed (or vice versa). Failing to check left < right && top < bottom before the third and fourth directions causes duplicate elements to be added when the matrix reduces to a single row or column.
Rectangular matrices with significantly different row and column counts can cause issues if the algorithm assumes square behavior. The spiral may terminate early or add extra elements if boundary checks do not account for both dimensions independently.
When using direction vectors, rotating incorrectly (e.g., counterclockwise instead of clockwise, or incorrect sign changes) produces a non-spiral traversal pattern. The correct clockwise rotation transforms (dr, dc) to (dc, -dr).