☰
蛇形矩阵算法详解:回字形与S形实现及边界控制技巧
2026/10/18 19:18:17 网站建设 项目流程

1. 蛇形矩阵到底是什么,为什么值得单独拎出来讲

蛇形矩阵这个题,在算法练习平台里属于那种“看起来简单、写起来卡壳、写完还想再优化”的经典题型。我第一次碰到它的时候,心里想的是:不就是把数字按顺序填进一个方格吗?结果真动手写,边界条件一多,脑子就开始打结。后来刷题刷多了才发现,蛇形矩阵其实是一类非常好的训练素材,它能同时考察你对二维数组操作、方向控制、边界判断和循环不变量的理解。

所谓蛇形矩阵,通常指的是把 1 到 n² 的数字,按照“蛇形”的路径填入一个 n×n 的方阵中。最常见的两种形态:一种是回字形蛇形,数字从外圈往内圈一圈一圈绕;另一种是S形蛇形,像蛇一样一行从左到右、下一行从右到左来回穿梭。不同平台、不同题目描述的“蛇形矩阵”可能指的不是同一种,这一点必须先确认清楚,否则你代码写得再漂亮,方向搞反了也是白搭。

这篇文章适合谁看?如果你正在准备算法面试、正在刷算法练习题、或者单纯想找一道题来练手二维数组的操控能力,那蛇形矩阵绝对值得你花时间吃透。我会从思路拆解、方向控制、边界处理、代码实现、常见坑点这几个维度,把这道题彻底讲清楚。你看完之后,应该能做到不看题解,自己从零推导出一份稳定可靠的实现。

提示:不同平台对“蛇形矩阵”的定义可能有差异,动手前一定要先看清楚题目给的示例输出,确认是回字形还是S形,这一步能帮你省下大量调试时间。

2. 两种主流蛇形矩阵的形态与核心差异

2.1 回字形蛇形矩阵的填充规律

回字形蛇形矩阵,也有人叫它螺旋矩阵。它的填充路径是这样的:从左上角出发,先向右走到底,再向下走到底,再向左走到底,再向上走到底,然后进入内圈,重复同样的动作,直到所有格子被填满。以 n=4 为例,输出是这样的:

1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7

你可以看到,数字沿着外圈顺时针绕了一圈,然后缩进到内圈继续绕。这种形态的核心在于四个边界的动态收缩:上边界、下边界、左边界、右边界,每走完一条边,对应的边界就往内收一格。

为什么这种题容易出错?因为边界收缩的时机和顺序非常讲究。你如果先更新边界再判断循环条件,或者先判断再更新,结果可能完全不同。我见过不少人写出来的代码,外圈没问题,一进内圈就多填一个或者少填一个,根源就在边界更新的顺序上。

2.2 S形蛇形矩阵的填充规律

S形蛇形矩阵就直观多了:第一行从左到右填,第二行从右到左填,第三行再从左到右,如此反复。以 n=4 为例:

1 2 3 4 8 7 6 5 9 10 11 12 16 15 14 13

这种形态的实现难度比回字形低不少,核心逻辑就是:遍历每一行,如果行号是偶数就正序填,奇数就倒序填。但别看它简单,里面也有坑——比如数字计数器在倒序填充时的递增方向,以及如何用最简洁的方式表达“正序/倒序”这个切换。

两种形态对比一下:

对比维度回字形蛇形矩阵S形蛇形矩阵
路径特点顺时针螺旋向内逐行来回穿梭
核心难点边界收缩与循环终止方向切换与索引控制
代码复杂度较高较低
常见变体逆时针、从中心向外逐列S形、对角线S形
训练价值边界控制、循环不变量索引映射、条件分支

搞清楚你要实现的是哪一种,后面的工作才有意义。下面我分别把两种形态的实现思路和代码都讲一遍。

3. 回字形蛇形矩阵的实现拆解与边界控制

3.1 四边界法的核心思路

实现回字形蛇形矩阵,最稳妥的方法是四边界法。定义四个变量:top、bottom、left、right,分别表示当前未填充区域的上、下、左、右边界。初始时top=0、bottom=n-1、left=0、right=n-1。

然后按照“右→下→左→上”的顺序循环填充:

  1. 从左到右填充上边界,填完后top加一
  2. 从上到下填充右边界,填完后right减一
  3. 从右到左填充下边界,填完后bottom减一
  4. 从下到上填充左边界,填完后left加一

每完成一轮,检查top <= bottom且left <= right是否仍然成立,成立就继续下一轮。

这个思路的好处是:你不需要在每一步都去判断“下一个格子有没有被填过”,只需要靠边界变量就能控制路径。代码写出来干净利落,不容易出错。

3.2 边界收缩的时机为什么这么关键

我重点说一下边界收缩的时机。以填充上边界为例,你从(top, left)填到(top, right),填完之后,这一行就再也不会被访问了,所以top可以安全地加一。但这里有个细节:你在填充上边界的时候,用的是当前的left和right,填完之后才更新top。如果你提前更新了top,那填充的起始行就错了。

再来看第三步填充下边界。这时候你从(bottom, right)填到(bottom, left),填完后bottom减一。但注意,执行到第三步之前,right已经在第二步中被减一了,所以这里的right是更新后的值。这个顺序不能乱。

还有一个容易忽略的点:在填充下边界和左边界之前,需要额外判断top <= bottom和left <= right。为什么?因为当矩阵的剩余区域只剩一行或者一列时,如果不加判断,可能会重复填充。比如 n=3 的矩阵,走到最后内圈只剩一个格子的时候,如果不加判断,四个步骤会依次执行,导致同一个格子被填多次。

def spiral_matrix(n): matrix = [[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 col in range(left, right + 1): matrix[top][col] = num num += 1 top += 1 # 从上到下填充右边界 for row in range(top, bottom + 1): matrix[row][right] = num num += 1 right -= 1 # 从右到左填充下边界 if top <= bottom: for col in range(right, left - 1, -1): matrix[bottom][col] = num num += 1 bottom -= 1 # 从下到上填充左边界 if left <= right: for row in range(bottom, top - 1, -1): matrix[row][left] = num num += 1 left += 1 return matrix

这段代码我用了很多次,实测下来非常稳定。你可以直接拿去跑,n=1 到 n=10 的输出都是对的。

3.3 方向数组法的替代方案

除了四边界法,还有一种方向数组法。思路是模拟一个“小人”在矩阵里走,每次按照当前方向走一步,如果下一步越界或者已经填过了,就换方向。方向顺序是右、下、左、上,用一个方向数组来表示:

directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]

这种方法的代码结构更通用,适合处理各种变形的路径问题。但它的缺点是需要额外的“已访问”判断,而且方向切换的逻辑如果写得不小心,容易陷入死循环。我个人建议:如果是单纯的回字形蛇形矩阵,用四边界法就够了;如果题目有变形(比如从中心向外螺旋、或者不规则形状),方向数组法更灵活。

4. S形蛇形矩阵的实现与索引映射技巧

4.1 逐行遍历的基本实现

S形蛇形矩阵的实现要简单得多。核心逻辑就是两层循环:外层遍历行,内层遍历列。如果当前行号是偶数(从0开始计数),就从左到右填;如果是奇数,就从右到左填。

def s_shape_matrix(n): matrix = [[0] * n for _ in range(n)] num = 1 for i in range(n): if i % 2 == 0: for j in range(n): matrix[i][j] = num num += 1 else: for j in range(n - 1, -1, -1): matrix[i][j] = num num += 1 return matrix

这段代码短小精悍,但里面有一个值得注意的细节:倒序填充时,j是从n-1递减到0,而num仍然是递增的。这意味着数字在矩阵中的位置是倒着的,但数值本身还是按顺序增长的。这一点如果搞反了,输出就会变成“数字倒着增长”,那就完全错了。

4.2 用数学公式直接计算每个位置的值

如果你想让代码更“优雅”一点,可以尝试用数学公式直接计算(i, j)位置上的值,而不需要模拟填充过程。对于S形蛇形矩阵,第i行的起始值是i * n + 1,如果i是偶数,位置j的值就是i * n + j + 1;如果i是奇数,位置j的值就是i * n + (n - j)。

def s_shape_formula(n): matrix = [] for i in range(n): if i % 2 == 0: row = [i * n + j + 1 for j in range(n)] else: row = [i * n + (n - j) for j in range(n)] matrix.append(row) return matrix

这种写法的好处是时间复杂度仍然是 O(n²),但常数更小,而且代码更简洁。缺点是可读性稍差,如果你是在面试中手写代码,建议还是用第一种模拟法,因为面试官更容易看懂你的思路。

4.3 S形矩阵的常见变形

S形蛇形矩阵还有一些变形,比如逐列S形:第一列从上到下,第二列从下到上,如此反复。实现思路和逐行S形完全对称,只需要把行和列的循环交换一下就行。

还有一种变形是对角线S形,数字沿着对角线方向来回填充。这种变形的难度会高不少,因为对角线的边界判断比行和列复杂。如果你已经掌握了基本的S形和回字形,可以拿对角线S形来练手,进一步提升对二维数组路径控制的理解。

5. 实操过程中最容易踩的五个坑

5.1 循环终止条件写错导致死循环

这是最常见的问题。在四边界法中,循环条件是top <= bottom and left <= right。如果你写成top < bottom and left < right,那么当矩阵只剩一行或一列时,循环会提前退出,导致部分格子没有被填充。反过来,如果你在边界更新后没有重新检查条件,可能会多填一轮,导致数组越界。

我的建议是:每次更新边界之后,都在心里默念一遍“现在的未填充区域是什么形状”,确认边界变量是否还满足top <= bottom和left <= right。这个习惯能帮你避开大部分边界相关的 bug。

5.2 奇数阶矩阵的中心格子被重复填充

当 n 是奇数时,矩阵最中心会有一个单独的格子。在四边界法中,当top == bottom且left == right时,这个格子会被填充。但如果你在第三步和第四步没有加if判断,这个格子可能会被填充两次,导致最终结果中某个数字被覆盖。

我实测过,n=3 和 n=5 是最容易出现这个问题的。解决办法就是在填充下边界和左边界之前,分别加上if top <= bottom和if left <= right的判断。

5.3 方向切换时索引越界

方向数组法中,每次移动之前都要检查下一步的位置是否在矩阵范围内,以及是否已经被访问过。如果你只检查了范围而没有检查是否已访问,就会陷入“在已填充区域来回走”的死循环。如果你只检查了已访问而没有检查范围,就会数组越界。

正确的做法是:先计算下一步的坐标,然后判断0 <= next_row < n且0 <= next_col < n且matrix[next_row][next_col] == 0。三个条件都满足才移动,否则换方向。

5.4 输出格式不符合题目要求

有些题目要求每个数字占固定宽度,比如%3d或者%4d,如果你直接打印数字,输出会参差不齐。还有些题目要求数字之间用空格分隔,行末不能有多余空格。这些格式细节虽然不影响算法正确性,但会影响你的提交结果。

我的习惯是:先在本地用题目给的示例输入跑一遍,把输出和示例逐字符对比。如果格式不对,调整打印语句就行,不要等到提交之后才发现问题。

5.5 把两种蛇形矩阵搞混

这个问题看起来很低级,但实际发生的频率不低。有些题目的描述比较模糊,只说“蛇形矩阵”,没有明确说是回字形还是S形。如果你没有仔细看示例输出,很容易写错方向。

我的做法是:拿到题目先看示例。如果示例的第一行是1 2 3 4,第二行是12 13 14 5,那就是回字形;如果第二行是8 7 6 5,那就是S形。确认清楚之后再动手,比写完再改要高效得多。

6. 常见问题速查与排查思路

问题现象可能原因排查方法
部分格子为0循环终止条件过早检查top <= bottom和left <= right
数字重复边界更新顺序错误确认每步填充后才更新对应边界
数组越界边界变量未及时收缩打印每轮边界值,观察是否越界
输出方向反了回字形与S形搞混对照示例输出确认形态
中心格子被覆盖缺少奇数阶判断在第三、四步加if判断
格式不整齐未设置输出宽度使用%3d或str(num).rjust(3)

除了上面这些,还有一个排查技巧:在循环内部打印当前的top、bottom、left、right和num,观察每一轮的变化。这个方法虽然原始,但对于理解边界收缩的过程非常有效。我当初就是靠打印调试,才真正搞懂了四边界法的运作机制。

注意:调试打印只在本地使用,提交代码前记得删掉,否则可能因为输出过多导致超时或格式错误。

7. 从蛇形矩阵延伸出的练习方向

蛇形矩阵本身不算难,但它是一个很好的起点。你可以基于它做很多延伸练习:

  • 逆时针回字形:把方向顺序改成“下→右→上→左”,其余逻辑不变。
  • 从中心向外螺旋:先确定中心位置,然后按照螺旋路径向外扩展,边界判断会更复杂。
  • 非方阵蛇形:输入 m×n 的矩阵,路径规则不变,但边界变量的初始值需要调整。
  • 带障碍物的蛇形:矩阵中某些格子不可访问,路径需要绕行,这时候方向数组法更有优势。
  • 蛇形矩阵的逆运算:给定一个蛇形矩阵,还原出原始的数字序列或者判断它是否是合法的蛇形矩阵。

这些变体在算法面试中出现的频率不低,尤其是“从中心向外螺旋”和“非方阵蛇形”,经常被用来考察候选人对边界控制的掌握程度。如果你能把基本形态写熟,再拿这些变体练手,二维数组类的题目基本就难不倒你了。

我个人在实际操作中的体会是:蛇形矩阵这类题,看题解看十遍不如自己动手写一遍。写完之后再改一改变体,比如把方向反过来、把方阵改成矩形、把起点换到中心,每改一次你都会对边界控制有新的理解。踩过几次坑之后,你会发现那些曾经让你头疼的边界条件,慢慢就变成了肌肉记忆。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询