Spiral Matrix II – Solution & Complexity

Solution Walkthrough

  1. Step 1: Understand the movement pattern

    • The fill direction cycles right, down, left, and up.
    • After finishing one side, the active unfilled rectangle becomes smaller.
  2. Step 2: Brute-force with direction vectors and visited cells

    • Keep a direction index and turn whenever the next cell would be out of bounds or already filled.
    • This is straightforward, but it needs an extra visited-state check on every step.
    def generate_matrix(n: int) -> list[list[int]]:
        matrix = [[0] * n for _ in range(n)]
        directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        row = col = direction = 0
        for value in range(1, n * n + 1):
            matrix[row][col] = value
            dr, dc = directions[direction]
            next_row = row + dr
            next_col = col + dc
            if not (0 <= next_row < n and 0 <= next_col < n) or matrix[next_row][next_col] != 0:
                direction = (direction + 1) % 4
                dr, dc = directions[direction]
                next_row = row + dr
                next_col = col + dc
            row, col = next_row, next_col
        return matrix
  3. Step 3: Shrink four boundaries instead of checking visited

    • Because the matrix is always square and we fill complete outer rings, we can track just top, bottom, left, and right.
    • That avoids a visited check on every move and makes the control flow more interview-friendly.
  4. Step 4: Fill one ring at a time

    • Write the top row, right column, bottom row, and left column, then move all four boundaries inward.
    • The same loop naturally handles the final center cell for odd n.
    def generate_matrix(n: int) -> list[list[int]]:
        if n <= 0:
            return []
        matrix = [[0] * n for _ in range(n)]
        top, bottom = 0, n - 1
        left, right = 0, 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 matrix
  5. Step 5: Dry run / ring trace

    Trace n = 3.

    ring actionmatrix state
    fill top row[[1,2,3],[0,0,0],[0,0,0]]
    fill right column[[1,2,3],[0,0,4],[0,0,5]]
    fill bottom row backward[[1,2,3],[0,0,4],[7,6,5]]
    fill left column upward[[1,2,3],[8,0,4],[7,6,5]]
    next inner ring[[1,2,3],[8,9,4],[7,6,5]]
  6. Step 6: Common mistakes and follow-ups

    • Forgetting to guard the bottom-row and left-column passes after shrinking boundaries.
    • Turning direction too early or too late in the visited-matrix approach.
    • Off-by-one errors on inclusive boundary loops.
    • Follow-up: how would you adapt the same idea to generate an m x n spiral instead of a square only?
  7. Step 7: Edge cases to test mentally

    • n = 1 should return a single-cell matrix.
    • n = 2 is the smallest case that touches all four directions.
    • Odd n leaves one center cell, which the same boundary loop fills naturally.
    • Larger n just repeats the same ring logic.
  8. Step 8: Final full solution and complexity

    Shrink four boundaries while filling one outer ring per loop. Every cell is written exactly once, so time is O(n^2) and the returned matrix uses O(n^2) space.

    def generate_matrix(n: int) -> list[list[int]]:
        if n <= 0:
            return []
    
        matrix = [[0] * n for _ in range(n)]
        top, bottom = 0, n - 1
        left, right = 0, 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 matrix

FAQ