螺旋矩阵 II 图解题解
这道题到底在问什么
- 输入
- n = 3
- 输出
- [[1,2,3],[8,9,4],[7,6,5]]
- 解释
- 从左上角开始,向右→向下→向左→向上,一圈圈往里绕着填。
最优解:一步一步想明白
- 3n=3,全是 0 待填这是 3×3 的空盘子(「·」表示还没填)。我们要把 1 到 9 按顺时针螺旋一格一格填进去,填完计数到 9 就结束。
- 4top / bottom / left / right不去记「现在朝哪个方向、要不要拐弯」那么乱,而是用四条边界 top/bottom/left/right 圈出「还没填的矩形」。每填完一条边,就把对应的边界往里收一格,矩形越缩越小。
- 5右 → 下 → 左 → 上每绕一圈就是这固定四步:走完上边 top 下移、走完右边 right 左移、走完下边 bottom 上移、走完左边 left 右移。然后用「top≤bottom 且 left≤right」判断里面还有没有格子要填。
- 6top=0 bottom=2 left=0 right=2开局四条边界框住整张表:top=0、bottom=2、left=0、right=2,要填的数字 num 从 1 开始。笔尖(紫色)停在左上角 (0,0),准备沿上边向右走。
- 7沿 top 行从左到右沿着上边 top=0 这一行,从 left 到 right 走。第一格 (0,0) 填 1,num 加到 2。
- 8沿 top 行从左到右继续向右,(0,1) 填 2。前一格 (0,0) 变蓝表示已填定,笔尖移到 (0,1)。
- 9上边走到头走到最右 (0,2) 填 3,上边到头了。上边这一行已经填满 1、2、3。
- 10top: 0 → 1上边填完,把 top 从 0 收到 1——第 0 行以后不用再碰。接着拐弯沿右边 right=2 这一列向下走,笔尖移到 (1,2)。
- 11沿 right 列从上到下拐弯向下,沿右边 right=2 这一列从 top 到 bottom 走。(1,2) 填 4,num 加到 5。
- 12右边走到底继续向下到底,(2,2) 填 5,右边到底了。整张表的右边一列 3、4、5 连成了。
- 13right: 2 → 1右边填完,把 right 从 2 收到 1。再拐弯沿下边 bottom=2 这一行向左走,笔尖移到 (2,1)。
- 14沿 bottom 行从右到左拐弯向左,沿下边 bottom=2 这一行从 right 到 left 走。(2,1) 填 6,num 加到 7。注意方向反过来了,从右往左。
- 15下边走到头继续向左到头,(2,0) 填 7,下边走完。最下面一行此刻是 7、6、5(从左看),正是螺旋绕回来的样子。
- 16bottom: 2 → 1下边填完,把 bottom 从 2 收到 1。最后拐弯沿左边 left=0 这一列向上走,笔尖移到 (1,0)。
- 17沿 left 列从下到上拐弯向上,沿左边 left=0 这一列从 bottom 到 top 走。(1,0) 填 8,num 加到 9。外面这一圈 1..8 已经绕满了。
- 18left: 0 → 1左边填完,把 left 从 0 收到 1。现在四条边界全收成 top=bottom=1、left=right=1——框住的只剩正中央 (1,1) 一格了,笔尖移过去。
- 19沿 top 行再走一格新一圈又从「沿 top 行向右」开始:(1,1) 填 9,num 到 10。这就是最中心那一格,1..9 全填满了。
- 20top 收到 2,下边/左边被 if 挡住填完中心后 top 收到 2。此时若没有那两个 if 守护,下边、左边的循环又会去碰中心格 (1,1)(红色)造成重填。正因为 top≤bottom 不成立,守护把它们挡住了,中心只被填一次。
- 21top>bottom,循环结束填完中心后 top 又收到 2,已经大于 bottom=1,「top≤bottom」不成立,循环退出。最终结果 [[1,2,3],[8,9,4],[7,6,5]]——一个漂亮的顺时针螺旋。
- 221..8 是最外一圈回看一眼螺旋的层次:紫色高亮的 1→2→3→4→5→6→7→8 是最外一圈,沿着边界顺时针绕了一整圈。
- 239 是最里一层外圈绕完,四条边界一起往里收,剩下的最里一层就是中心 9。n 更大时会一圈圈往里收很多层,规律完全一样:右→下→左→上,每走完一边收一条边界。
- 24下边和左边要加判断当 n 是奇数、收到最后只剩一行或一列时,上边和右边已经把它填了。如果不加判断又去走下边、左边,就会重复填或越界。所以走下边、左边前各补一个 if 守护。
- 27记住这一句螺旋遍历类题的统一套路:用四条边界圈住「还没处理的矩形」,按右→下→左→上固定顺序走,每走完一条边就把那条边界往里收,矩形缩到空为止。读、填都一样。
- 29n 奇数收到单行时假设收到最后只剩中心一格 (1,1)(红色):上边那一步已经把它填成 9。若走下边、左边时不加 if 判断,会再去写这一格,导致数字被覆盖错乱——这正是要加守护的原因。
⚠️ 容易写错的地方
✗ 错:走下边、左边不加 if 守护
✓ 对:走下边前判 top≤bottom,走左边前判 left≤right
n 为奇数收到单行/单列时,不判会重复填或越界
✗ 错:收缩边界忘了在走完那条边之后立刻做
✓ 对:走完上边马上 top++,走完右边马上 right--
边界没及时收,下一条边会从错误的起点走、踩到已填格
✗ 错:把方向写错,比如下边忘了从右到左
✓ 对:下边 j 从 right 递减到 left,左边 i 从 bottom 递减到 top
螺旋是顺时针,下边和左边的循环方向必须是反向递减
完整代码(Python / C++ / Java)
Python
class Solution:
def generateMatrix(self, n):
m = [[0] * n for _ in range(n)]
top, bottom, left, right = 0, n - 1, 0, n - 1
num = 1
while top <= bottom and left <= right:
for j in range(left, right + 1):
m[top][j] = num; num += 1
top += 1
for i in range(top, bottom + 1):
m[i][right] = num; num += 1
right -= 1
if top <= bottom:
for j in range(right, left - 1, -1):
m[bottom][j] = num; num += 1
bottom -= 1
if left <= right:
for i in range(bottom, top - 1, -1):
m[i][left] = num; num += 1
left += 1
return mC++
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> m(n, vector<int>(n, 0));
int top = 0, bottom = n - 1, left = 0, right = n - 1;
int num = 1;
while (top <= bottom && left <= right) {
for (int j = left; j <= right; j++) m[top][j] = num++;
top++;
for (int i = top; i <= bottom; i++) m[i][right] = num++;
right--;
if (top <= bottom) {
for (int j = right; j >= left; j--) m[bottom][j] = num++;
bottom--;
}
if (left <= right) {
for (int i = bottom; i >= top; i--) m[i][left] = num++;
left++;
}
}
return m;
}
};Java
class Solution {
public int[][] generateMatrix(int n) {
int[][] m = new int[n][n];
int top = 0, bottom = n - 1, left = 0, right = n - 1;
int num = 1;
while (top <= bottom && left <= right) {
for (int j = left; j <= right; j++) m[top][j] = num++;
top++;
for (int i = top; i <= bottom; i++) m[i][right] = num++;
right--;
if (top <= bottom) {
for (int j = right; j >= left; j--) m[bottom][j] = num++;
bottom--;
}
if (left <= right) {
for (int i = bottom; i >= top; i--) m[i][left] = num++;
left++;
}
}
return m;
}
}复杂度
时间
O(n²)
每个格子恰好被填一次,总共 n² 个格子
空间
O(1)
除返回的矩阵外,只用了几个边界变量,额外空间常数
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 螺旋矩阵 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
和「螺旋矩阵 I」(给矩阵按螺旋读出)有什么区别?+
框架完全一样,都是四边界右→下→左→上收缩。I 是把读到的值 append 到结果数组,II 是把递增的 num 写进矩阵。一个是读、一个是写,循环结构一模一样。
除了四边界,还有别的写法吗?+
可以用「方向数组 + 转向」:维护当前方向 (dx,dy),下一格越界或已填过就顺时针转 90 度。代码更短但要判越界和访问标记,边界法更直观不易错。
如果要按逆时针螺旋填呢?+
把四步顺序改成「下→右→上→左」或「右→上→左→下」之一即可,对应调整每条边的遍历方向和边界收缩,骨架不变。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 螺旋矩阵 II 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。