A clear guide to generating an n x n matrix filled from 1 to n squared in spiral order.
Problem Restatement
We are given a positive integer n.
We need to generate an n x n matrix filled with numbers from 1 to n^2 in spiral order.
The spiral starts at the top-left cell and moves:
- Right
- Down
- Left
- Up
Then it repeats inward until every cell is filled.
The official constraint is 1 <= n <= 20.
Input and Output
| Item | Meaning |
|---|---|
| Input | A positive integer n |
| Output | An n x n matrix |
| Values | Integers from 1 to n^2 |
| Fill order | Clockwise spiral from the top-left corner |
Function shape:
def generateMatrix(n: int) -> list[list[int]]:
...Examples
For:
n = 3The answer is:
[
[1, 2, 3],
[8, 9, 4],
[7, 6, 5],
]The filling order is:
1 -> 2 -> 3
|
8 -> 9 4
| |
7 <- 6 <- 5For:
n = 1The answer is:
[[1]]There is only one cell, so we place 1.
First Thought: Simulate Movement
One approach is to walk through the matrix cell by cell.
Start at (0, 0), move right, and place increasing numbers. When the next cell is outside the matrix or already filled, turn clockwise.
This works, but it needs extra checks against filled cells.
A boundary-based method is easier to explain and less error-prone.
Key Insight
The matrix can be filled layer by layer.
Each layer has four boundaries:
| Boundary | Meaning |
|---|---|
top | First unfilled row |
bottom | Last unfilled row |
left | First unfilled column |
right | Last unfilled column |
For each layer:
- Fill the top row from left to right.
- Move
topdown. - Fill the right column from top to bottom.
- Move
rightleft. - Fill the bottom row from right to left.
- Move
bottomup. - Fill the left column from bottom to top.
- Move
leftright.
Since the matrix is square, this process eventually reaches the center.
Algorithm
Create an empty matrix filled with zeros:
matrix = [[0] * n for _ in range(n)]Initialize boundaries:
top = 0
bottom = n - 1
left = 0
right = n - 1Initialize the next value:
value = 1While the boundaries are still valid:
top <= bottom and left <= rightFill the current outer layer in four directions.
After writing each number, increment value.
Return the filled matrix.
Correctness
The algorithm maintains a rectangle of unfilled cells bounded by top, bottom, left, and right.
During each loop, it fills the outer edge of that rectangle in clockwise order. After the top row is filled, top moves inward. After the right column is filled, right moves inward. The same happens for the bottom row and left column.
No filled row or column is visited again because each boundary moves inward immediately after that edge is filled.
Every loop removes one outer layer from the unfilled region. Since the matrix has finitely many layers, the process ends after all cells are filled.
The value starts at 1 and increases by one after each cell write. Since the matrix has n^2 cells and each cell is written once, the final matrix contains exactly the numbers from 1 to n^2 in clockwise spiral order.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n^2) | The matrix has n^2 cells, and each cell is filled once |
| Space | O(1) extra | Apart from the returned matrix, only a few variables are used |
The returned matrix itself uses O(n^2) space.
Implementation
class Solution:
def generateMatrix(self, n: int) -> list[list[int]]:
matrix = [[0] * n for _ in range(n)]
top = 0
bottom = n - 1
left = 0
right = n - 1
value = 1
while top <= bottom and left <= right:
for col in range(left, right + 1):
matrix[top][col] = value
value += 1
top += 1
for row in range(top, bottom + 1):
matrix[row][right] = value
value += 1
right -= 1
if top <= bottom:
for col in range(right, left - 1, -1):
matrix[bottom][col] = value
value += 1
bottom -= 1
if left <= right:
for row in range(bottom, top - 1, -1):
matrix[row][left] = value
value += 1
left += 1
return matrixCode Explanation
We first create the result matrix:
matrix = [[0] * n for _ in range(n)]Then define the current unfilled rectangle:
top = 0
bottom = n - 1
left = 0
right = n - 1The next number to place is:
value = 1The loop continues while at least one row and one column remain:
while top <= bottom and left <= right:First, fill the top row:
for col in range(left, right + 1):
matrix[top][col] = value
value += 1
top += 1Then fill the right column:
for row in range(top, bottom + 1):
matrix[row][right] = value
value += 1
right -= 1Before filling the bottom row, check that a row still remains:
if top <= bottom:Then fill it from right to left:
for col in range(right, left - 1, -1):
matrix[bottom][col] = value
value += 1
bottom -= 1Before filling the left column, check that a column still remains:
if left <= right:Then fill it from bottom to top:
for row in range(bottom, top - 1, -1):
matrix[row][left] = value
value += 1
left += 1When the boundaries cross, all cells have been filled.
Testing
def run_tests():
s = Solution()
assert s.generateMatrix(1) == [
[1],
]
assert s.generateMatrix(2) == [
[1, 2],
[4, 3],
]
assert s.generateMatrix(3) == [
[1, 2, 3],
[8, 9, 4],
[7, 6, 5],
]
assert s.generateMatrix(4) == [
[1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
[10, 9, 8, 7],
]
print("all tests passed")
run_tests()| Test | Why |
|---|---|
n = 1 | Smallest input |
n = 2 | Small even-sized matrix |
n = 3 | Standard example with center cell |
n = 4 | Larger even-sized matrix |