#59 矩阵操作 中等

螺旋矩阵 II

在 LeetCode 上查看 ↗

🎧 语音讲解

开车或通勤时可听,跟着思路走一遍

速度

📋 题目描述

给你一个正整数 n,生成一个包含 1 所有元素,且元素按顺时针螺旋顺序排列的 n × n 正方形矩阵 matrix

示例 1

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2

输入:n = 1
输出:[[1]]

💭 模拟答题者思考

1. 最直接:模拟螺旋路径——从 (0,0) 出发,方向依次为右、下、左、上,遇边界或已填格就转向;需要 visited[n][n] 或判 0,时间 O(n²),额外空间 O(n²)。

2. 重复在哪里?方向数组写法每步都要判「是否出界 / 是否已填」,n=1 或单行单列时转向逻辑容易写错,调试成本高。

3. 关键转化:本题与 #54「螺旋矩阵」互为逆过程——#54 按边界剥洋葱元素,本题按同样顺序数字;复用「四边 + 边界收缩」框架,把 ans.append 换成 matrix[i][j]=num; num++ 即可。

4. 手推 n=3:第一圈写入 1,2,3 → 4 → 5 → 6 → 7,8;收缩后第二圈只剩中心,顶行写入 9,得到 [[1,2,3],[8,9,4],[7,6,5]]。

5. 边界条件:底行仅在 top < bottom 时填充(避免与顶行重复);左列仅在 left < right 时填充(避免与右列重复)。n=1 时只走顶边一圈即结束。

🧠 变量语义(先读这三句再编码)

变量类型语义(三句法)
matrixlist<list<int>>定义:待填充的 n×n 结果矩阵,初始为 0
维护:按顺时针螺旋顺序,从外圈到内圈逐格写入 1..n²
更新:每写入一格 matrix[i][j] = numnum++,直至 num > n²
numint定义:下一个要写入矩阵的整数,初始为 1
维护:沿当前圈的顶行→右列→底行→左列顺序递增赋值
更新:每填一格 num += 1;当 num > n² 时全部填完,可结束
top, bottomint定义:当前待填充子矩阵的上、下边界行号(含端点)
维护:每完成一圈螺旋后 top++bottom--,向内收缩一行
更新:初始 top=0, bottom=n-1;循环条件 num ≤ n² 自然终止
left, rightint定义:当前待填充子矩阵的左、右边界列号(含端点)
维护:每完成一圈螺旋后 left++right--,向内收缩一列
更新:初始 left=0, right=n-1;与 top/bottom 共同框定当前「洋葱圈」
i, jint定义:沿当前边扫描时的行、列下标
维护:四条边分别用 for 推进——上从左到右、右从上到下、下从右到左、左从下到上
更新:每步写入 matrix[i][j] 并递增 num,与 #54 读螺旋顺序的遍历方向完全一致,只是从「读」变为「写」

⌨️ 落码步骤

1. 创建 n×n 的零矩阵,初始化 num=1top=0, bottom=n-1, left=0, right=n-1

2. 当 num ≤ n² 时循环(还有数字待填)

3. 上边for j in range(left, right+1),依次 matrix[top][j]=num; num+=1

4. 右边for i in range(top+1, bottom+1),依次 matrix[i][right]=num; num+=1

5. 若 top < bottom下边right-1left 逆序填充 matrix[bottom][j]

6. 若 left < right左边bottom-1top+1 逆序填充 matrix[i][left]

7. 收缩边界 top++, bottom--, left++, right--,进入下一圈

8. 返回 matrix

💻 代码实现

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        matrix = [[0] * n for _ in range(n)]
        num = 1
        top, bottom = 0, n - 1
        left, right = 0, n - 1

        while num <= n * n:
            # 上边:从左到右
            for j in range(left, right + 1):
                matrix[top][j] = num
                num += 1
            # 右边:从上到下(跳过顶角,已在上边填入)
            for i in range(top + 1, bottom + 1):
                matrix[i][right] = num
                num += 1
            # 下边:从右到左(仅当还有多行时)
            if top < bottom:
                for j in range(right - 1, left - 1, -1):
                    matrix[bottom][j] = num
                    num += 1
            # 左边:从下到上(仅当还有多列时)
            if left < right:
                for i in range(bottom - 1, top, -1):
                    matrix[i][left] = num
                    num += 1
            top += 1
            bottom -= 1
            left += 1
            right -= 1

        return matrix
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> matrix(n, vector<int>(n, 0));
        int num = 1;
        int top = 0, bottom = n - 1, left = 0, right = n - 1;

        while (num <= n * n) {
            // 上边:从左到右
            for (int j = left; j <= right; j++) {
                matrix[top][j] = num++;
            }
            // 右边:从上到下
            for (int i = top + 1; i <= bottom; i++) {
                matrix[i][right] = num++;
            }
            // 下边:从右到左(仅当还有多行时)
            if (top < bottom) {
                for (int j = right - 1; j >= left; j--) {
                    matrix[bottom][j] = num++;
                }
            }
            // 左边:从下到上(仅当还有多列时)
            if (left < right) {
                for (int i = bottom - 1; i > top; i--) {
                    matrix[i][left] = num++;
                }
            }
            top++;
            bottom--;
            left++;
            right--;
        }
        return matrix;
    }
};
// 时间 O(n²),空间 O(1)(不计输出)

📈 复杂度分析

时间复杂度 O(n²)
空间复杂度 O(1)(不计输出矩阵)

⚠️ 常见坑

忘记「单行/单列」判断:走完顶行和右列后,若 top == bottom 仍填底行,会把同一格重复写入;必须用 if (top < bottom)if (left < right) 保护。

与 #54 混淆方向:#54 是读已有矩阵,本题是写新矩阵;遍历顺序相同,但 #54 用 append,本题用递增 num 赋值。

右边循环应从 top+1 开始、左边从 bottom-1top+1,否则四个角的数字会被重复写入或覆盖。

🔍 必测边界 Case

Case 1:n = 1
n = 1 → [[1]](只填顶边一格,循环一次即结束)
Case 2:n = 2
n = 2 → [[1,2],[4,3]](两圈:外圈 1,2,3,4 中缺中心?实际 2×2 一圈填完 4 个数)
Case 3:n = 3 奇数方阵
n = 3 → [[1,2,3],[8,9,4],[7,6,5]](中心 9 在第二圈单独填入)
Case 4:n = 4 偶数方阵
外圈填 1..12,内圈填 13..16(无单独中心格,全靠边界收缩)
Case 5:n = 20 上限
共 400 格O(n²) 四边循环仍高效,无需担心超时