54. 螺旋矩阵#
生活中的螺旋#
你有没有注意过,生活中螺旋的形状随处可见?比如蜗牛壳的螺旋纹路、向日葵中心的螺旋排列、甚至是停车场的螺旋坡道。这种由外向内(或由内向外)的螺旋路径,不仅是大自然的奇妙设计,也启发了我们解决一些编程问题。
问题描述#
题目目标#
LeetCode第54题”螺旋矩阵”是这样描述的:给你一个 m x n 的矩阵,请按照顺时针螺旋顺序,返回矩阵中的所有元素。
示例 1#
输入:
matrix = [[1,2,3],
[4,5,6],
[7,8,9]]text输出:
[1,2,3,6,9,8,7,4,5]
想象你在逛一个方形的购物中心,从正门开始,按顺时针方向走完每条走廊,最终到达中心的休息区。这就是一个完美的螺旋路径!text矩阵示意:
1 2 3
4 5 6
7 8 9text说明: 图示把输入结构和输出结果并排展开后,会更容易直接看清题目的变化过程。
补充说明#
- 矩阵按行给出,外层数组表示所有行,内层数组表示每一行的元素。
最直观的解法:模拟螺旋过程#
就像我们在购物中心逛街一样,最直观的方法是:按照右、下、左、上的顺序,一步步”走”过矩阵的每个元素。
让我们用一个简单的3×3矩阵来理解:
1 2 3 →→→ 第一步:向右走到底
4 5 6 ↓ 第二步:向下走到底
7 8 9 ←←← 第三步:向左走到底
↑ 第四步:向上走到顶plaintext优化解法:边界收缩#
仔细观察,我们其实是在不断缩小遍历的范围。就像削苹果皮,从外面一圈圈向内削去。我们可以维护四个边界(上、下、左、右),每走完一个方向就收缩对应的边界。
边界收缩的原理#
想象你在玩一个迷宫游戏:
- 一开始,你可以在整个迷宫中移动
- 走完一条路径后,那条路就会消失(边界收缩)
- 在剩余的空间中继续移动
- 直到走完所有路径
示例运行#
用一个3×3的例子来说明:
初始状态:
上边界(top)=0, 下边界(bottom)=2
左边界(left)=0, 右边界(right)=2
第一圈:
1. 向右:(0,0)->(0,2) [1,2,3]
上边界+1
2. 向下:(0,2)->(2,2) [6,9]
右边界-1
3. 向左:(2,2)->(2,0) [8,7]
下边界-1
4. 向上:(2,0)->(1,0) [4]
左边界+1
第二圈:
只剩中间的5,直接添加plaintextJava代码实现#
public List<Integer> spiralOrder(int[][] matrix) {
// 用于按螺旋顺序保存遍历结果
List<Integer> result = new ArrayList<>();
// 边界条件:矩阵为空或没有行时,直接返回空结果
if (matrix == null || matrix.length == 0) {
return result;
}
// top:当前可遍历区域的上边界(包含)
int top = 0;
// bottom:当前可遍历区域的下边界(包含)
int bottom = matrix.length - 1;
// left:当前可遍历区域的左边界(包含)
int left = 0;
// right:当前可遍历区域的右边界(包含)
int right = matrix[0].length - 1;
// 当上下边界和左右边界仍然合法时,说明还有元素未遍历
while (top <= bottom && left <= right) {
// 第 1 步:从左到右遍历当前上边界这一行
for (int i = left; i <= right; i++) {
// 依次加入 top 行、列 i 的元素
result.add(matrix[top][i]);
}
// 上边界已遍历完,向内收缩一行
top++;
// 第 2 步:从上到下遍历当前右边界这一列
for (int i = top; i <= bottom; i++) {
// 依次加入行 i、right 列的元素
result.add(matrix[i][right]);
}
// 右边界已遍历完,向内收缩一列
right--;
// 第 3 步前先判断:收缩后可能已经没有剩余行,避免重复/越界
if (top <= bottom) {
// 从右到左遍历当前下边界这一行
for (int i = right; i >= left; i--) {
// 依次加入 bottom 行、列 i 的元素
result.add(matrix[bottom][i]);
}
// 下边界已遍历完,向内收缩一行
bottom--;
}
// 第 4 步前再判断:收缩后可能已经没有剩余列,避免重复/越界
if (left <= right) {
// 从下到上遍历当前左边界这一列
for (int i = bottom; i >= top; i--) {
// 依次加入行 i、left 列的元素
result.add(matrix[i][left]);
}
// 左边界已遍历完,向内收缩一列
left++;
}
}
// 返回完整的螺旋遍历结果
return result;
}java实用技巧总结#
解决螺旋矩阵问题的关键点:
- 明确移动方向的顺序(右->下->左->上)
- 正确维护和更新边界
- 注意边界条件的判断
- 处理特殊情况(如只有一行或一列)
类似的问题还有:
- 生成螺旋矩阵
- 对角线遍历
- 顺时针打印矩阵
小结#
通过螺旋矩阵这道题,我们学会了如何用编程来模拟现实生活中的螺旋路径。这种思维方式不仅能解决算法题,在处理图像处理、游戏开发等实际问题时也很有用。记住,当遇到需要特定顺序遍历矩阵的问题时,可以考虑使用边界收缩的方法,让代码更加清晰和高效!