螺旋矩阵是LeetCode上经典的二维数组操作题目(编号59),要求按照顺时针螺旋顺序填充一个n×n的方阵。这个问题看似简单,但涉及多个关键编程概念:边界控制、循环不变量原则、二维数组遍历策略等。作为面试高频题,掌握其解法能显著提升对矩阵操作的理解能力。
我在实际解题中发现,许多初学者容易陷入"边界混乱"的困境——要么重复填充元素,要么遗漏角落位置。本文将分享一种清晰可靠的实现方案,重点讲解如何通过"分层处理+左闭右开"的策略规避这些陷阱。
螺旋填充的核心观察是:n×n矩阵可以看作由若干层同心环组成,每层都是一个完整的"圈"。对于n=3的矩阵:
code复制1 → 2 → 3
↓
8 → 9 4
↑ ↓
7 ← 6 ← 5
只需要填充最外层(数字1-8)和中心点(数字9)两个部分。由此得出关键结论:
每层循环需要依次处理四条边:
为保持循环不变量(每次操作的一致性),采用左闭右开区间原则:
python复制def generateMatrix(n: int) -> List[List[int]]:
# 初始化n×n结果矩阵
res = [[0] * n for _ in range(n)]
start_x, start_y = 0, 0 # 每圈起始坐标
loop = n // 2 # 循环次数
mid = n // 2 # 中心点坐标
count = 1 # 填充数字
关键点说明:
res矩阵用列表推导式创建,比[[0]*n]*n更安全(避免浅拷贝问题)loop计算循环轮数,mid用于后续奇数特判count从1开始递增,符合题目要求的填充顺序python复制 for offset in range(1, loop + 1): # offset控制每圈边界
# 上边:从左到右
for j in range(start_y, n - offset):
res[start_x][j] = count
count += 1
# 右边:从上到下
for i in range(start_x, n - offset):
res[i][n - offset] = count
count += 1
# 下边:从右到左
for j in range(n - offset, start_y, -1):
res[n - offset][j] = count
count += 1
# 左边:从下到上
for i in range(n - offset, start_x, -1):
res[i][start_y] = count
count += 1
start_x += 1 # 更新下一圈起始坐标
start_y += 1
代码细节解析:
offset从1开始,确保n-offset正确形成左闭右开区间(start_x, start_y)向内缩进1python复制 if n % 2 != 0: # n为奇数时填充中心点
res[mid][mid] = count
return res
当n为奇数时,中心点坐标为(mid, mid)。例如n=3时,中心位置是(1,1),填充数字9。
虽然算法已最优,但代码可读性可进一步优化:
enumerate简化循环计数| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 角落元素重复填充 | 区间未采用左闭右开 | 检查每条边的终止条件 |
| 中心点未正确填充 | 忘记n为奇数判断 | 添加if n % 2 != 0分支 |
| 矩阵未填满 | 循环次数不足 | 确认loop = n // 2 |
| 数字顺序错乱 | 四条边顺序错误 | 确保上→右→下→左顺序 |
打印中间状态:在每圈循环后打印矩阵,观察填充进度
python复制print(f"After loop {offset}:")
for row in res:
print(row)
小规模测试:优先测试n=1,2,3等小案例,快速验证边界条件
可视化辅助:在纸上画出矩阵索引,标注循环范围
虽然本题限定为方阵,但类似思路可推广到m×n矩形:
min(m,n)//2这种变体在图像处理中很常见,例如螺旋遍历像素矩阵。掌握基础方阵解法后,可以尝试解决LeetCode 54题(螺旋矩阵)。
我在实际编码中发现,保持清晰的边界定义比追求代码简洁更重要。曾经为了减少变量使用而合并start_x和start_y,结果导致调试困难。后来坚持为每个关键参数赋予明确语义,代码可维护性大幅提升。