LeetCode 热题 100 之 54.螺旋矩阵

解题思路(边界模拟法)
我们可以通过维护四个边界(上、下、左、右)来模拟顺时针螺旋遍历的过程:
- 从左到右遍历当前上边界的行,然后上边界向下移动。
- 从上到下遍历当前右边界的列,然后右边界向左移动。
- 如果上下边界仍有未遍历的行,则从右到左遍历当前下边界的行,然后下边界向上移动。
- 如果左右边界仍有未遍历的列,则从下到上遍历当前左边界的列,然后左边界向右移动。
- 重复以上步骤,直到所有边界交叉,遍历结束。
Java 代码实现
public class Solution { public List<Integer> spiralOrder(int[][] matrix) { List<Integer> res = new ArrayList<>(); if (matrix == null || matrix.length == 0) { return res; } int top = 0; int bottom = matrix.length - 1; int left = 0; int right = matrix[0].length - 1; while (top <= bottom && left <= right) { // 1. 从左到右遍历上边界 for (int j = left; j <= right; j++) { res.add(matrix[top][j]); } top++; // 2. 从上到下遍历右边界 for (int i = top; i <= bottom; i++) { res.add(matrix[i][right]); } right--; // 3. 如果还有行,从右到左遍历下边界 if (top <= bottom) { for (int j = right; j >= left; j--) { res.add(matrix[bottom][j]); } bottom--; } // 4. 如果还有列,从下到上遍历左边界 if (left <= right) { for (int i = bottom; i >= top; i--) { res.add(matrix[i][left]); } left++; } } return res; } } 
复杂度分析
- 时间复杂度:O (mn),矩阵中的每个元素都被访问一次。
- 空间复杂度:O (1),除了存储结果的列表外,我们只使用了常数级别的额外空间。
官方解法
class Solution { public List<Integer> spiralOrder(int[][] matrix) { // 1. 初始化结果列表,用于存储螺旋遍历的元素 List<Integer> order = new ArrayList<Integer>(); // 2. 边界校验:如果矩阵为空/行数为0/列数为0,直接返回空列表 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return order; } // 3. 定义基础变量 int rows = matrix.length; // 矩阵的行数 int columns = matrix[0].length; // 矩阵的列数 boolean[][] visited = new boolean[rows][columns]; // 标记矩阵元素是否被访问过(避免重复遍历) int total = rows * columns; // 矩阵总元素数(遍历终止条件) int row = 0, column = 0; // 当前遍历的行、列坐标(初始在左上角) // 4. 定义四个移动方向:右(0,1)、下(1,0)、左(0,-1)、上(-1,0)(顺时针顺序) int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; int directionIndex = 0; // 当前方向的索引(初始为“右”) // 5. 遍历所有元素(循环total次) for (int i = 0; i < total; i++) { // 5.1 将当前元素加入结果列表,并标记为已访问 order.add(matrix[row][column]); visited[row][column] = true; // 5.2 计算下一个位置的坐标(按当前方向前进) int nextRow = row + directions[directionIndex][0]; int nextColumn = column + directions[directionIndex][1]; // 5.3 检查下一个位置是否合法:越界 或 已访问 → 需要切换方向 if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) { directionIndex = (directionIndex + 1) % 4; // 切换方向(取模4保证循环) } // 5.4 更新当前坐标(按新方向/原方向前进) row += directions[directionIndex][0]; column += directions[directionIndex][1]; } // 6. 返回遍历结果 return order; } }扩展
一、核心应用场景
1. 图形 / 图像处理领域(最常见)
- 场景:在图像编辑、计算机视觉中,经常需要按螺旋顺序处理像素(比如对图像局部区域做模糊、锐化、边缘检测,或提取特定区域的像素特征)。
- 举例:
- 对一张照片的某个矩形区域,从外到内螺旋式调整像素亮度 / 对比度,实现 “渐变晕影” 效果;
- 医学影像(如 CT、MRI 切片)分析中,螺旋遍历病灶区域的像素,提取纹理特征辅助诊断。
- 举例:
- 为什么用螺旋遍历:相比逐行 / 逐列遍历,螺旋遍历能更贴合 “从外围到核心” 的分析逻辑,比如先分析病灶边缘,再深入核心区域。
2. 数据可视化 / UI 交互
- 场景:前端 / 移动端的可视化组件开发中,螺旋布局的图表、动画效果需要基于螺旋遍历的逻辑实现。
- 举例:
- 螺旋式排列的数字仪表盘、进度条(比如电商平台的 “销量螺旋增长” 可视化图表);
- 游戏开发中,敌人从外围螺旋式向玩家角色移动的路径规划(本质是按螺旋顺序遍历二维地图坐标)。
- 举例:
3. 矩阵数据处理 / 算法题解(工程 + 面试)
- 场景:后端数据处理中,对二维结构化数据(如表格、矩阵型传感器数据)做螺旋式读取 / 写入。
- 举例:
- 工业传感器阵列(如温度、压力传感器组成的二维网格),按螺旋顺序采集数据,确保 “先外围后核心” 的采样优先级;
- 数据库中二维报表数据的导出 / 转换(比如将螺旋遍历的结果生成特定格式的报表)。
- 举例:
- 面试价值:这是算法面试的经典题(LeetCode 54 题),掌握它能体现你对 “边界控制”“循环逻辑” 的理解,而这类边界处理能力是开发中处理复杂数据结构的基础(比如处理分页、多维数组分片)。
4. 硬件 / 嵌入式开发
- 场景:对二维阵列硬件(如 LED 点阵屏、键盘矩阵)的驱动控制。
- 举例:
- LED 点阵屏实现螺旋式滚动显示文字 / 图案(比如从屏幕外围到中心逐步点亮像素);
- 矩阵键盘的扫描策略(按螺旋顺序扫描按键,优化响应效率)。
- 举例:
二、实际应用示例(简化代码场景)
以 “LED 点阵屏螺旋点亮” 为例,核心逻辑复用螺旋遍历的边界控制思想:
// 模拟LED点阵屏(5x5),按螺旋顺序点亮像素(1=亮,0=灭) public class LedMatrix { public static void main(String[] args) { int[][] ledMatrix = new int[5][5]; // 初始全灭(0) spiralLight(ledMatrix); // 打印点亮后的点阵 for (int[] row : ledMatrix) { for (int pixel : row) { System.out.print(pixel + " "); } System.out.println(); } } // 螺旋点亮逻辑(复用原算法的边界控制) public static void spiralLight(int[][] matrix) { if (matrix == null || matrix.length == 0) return; int top = 0, bottom = matrix.length - 1; int left = 0, right = matrix[0].length - 1; int lightFlag = 1; // 标记是否点亮 while (top <= bottom && left <= right) { // 从左到右点亮上边界 for (int j = left; j <= right; j++) { matrix[top][j] = lightFlag; } top++; // 从上到下点亮右边界 for (int i = top; i <= bottom; i++) { matrix[i][right] = lightFlag; } right--; // 从右到左点亮下边界(判断是否有行) if (top <= bottom) { for (int j = right; j >= left; j--) { matrix[bottom][j] = lightFlag; } bottom--; } // 从下到上点亮左边界(判断是否有列) if (left <= right) { for (int i = bottom; i >= top; i--) { matrix[i][left] = lightFlag; } left++; } } } } 输出效果(5x5 点阵全被螺旋式点亮为 1):
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 如果调整lightFlag为按遍历顺序递增(1、2、3...25),就能看到明显的螺旋数字排列,对应 LED 屏的螺旋显示效果。
总结
- 螺旋遍历矩阵的核心价值是按 “从外到内、顺时针” 的顺序处理二维结构数据,适配 “外围优先” 的业务逻辑;
- 实际应用集中在图形图像处理、数据可视化、硬件驱动等领域,同时也是算法能力的经典考察点;
- 其核心的 “边界收缩” 思想(top/bottom/left/right 控制)可迁移到各类二维数据的遍历场景(如分页处理、区域裁剪)。
