当前位置: 首页 > news >正文

LeetCode54螺旋矩阵算法详解

文章目录

  • 螺旋矩阵算法详解
    • 题目描述
      • 示例
    • 算法核心思想
      • 关键概念:四边界控制
      • 遍历顺序
    • 算法实现
    • 算法步骤详解
      • 示例:3x3矩阵 [[1,2,3],[4,5,6],[7,8,9]]
    • 边界处理的关键点
      • 1. 为什么步骤3和4需要额外判断?
      • 2. 边界情况分析
        • 单行矩阵:[[1,2,3,4,5]]
        • 单列矩阵:[[1],[2],[3]]
        • 2x2矩阵:[[1,2],[3,4]]
    • 可视化理解
      • 边界收缩过程
    • 复杂度分析
    • 常见错误
      • 1. 忘记边界检查
      • 2. 边界更新顺序错误
    • 总结

螺旋矩阵算法详解

题目描述

给你一个 m 行 n 列的矩阵 matrix,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]可视化:
1 → 2 → 3↓
4 → 5   6
↑       ↓
7 ← 8 ← 9

算法核心思想

关键概念:四边界控制

通过维护四个边界来控制遍历范围:

  • top:上边界
  • bottom:下边界
  • left:左边界
  • right:右边界

遍历顺序

按照顺时针方向,循环执行四个步骤:

  1. 从左到右 遍历上边界
  2. 从上到下 遍历右边界
  3. 从右到左 遍历下边界
  4. 从下到上 遍历左边界

每完成一个方向的遍历,就收缩对应的边界。

算法实现

public List<Integer> spiralOrder(int[][] matrix) {List<Integer> result = new ArrayList<>();if (matrix.length == 0) return result;// 定义四个边界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 col = left; col <= right; col++) {result.add(matrix[top][col]);}top++; // 上边界下移// 2. 从上到下遍历右边界for (int row = top; row <= bottom; row++) {result.add(matrix[row][right]);}right--; // 右边界左移// 3. 从右到左遍历下边界(需要检查是否还有行)if (top <= bottom) {for (int col = right; col >= left; col--) {result.add(matrix[bottom][col]);}bottom--; // 下边界上移}// 4. 从下到上遍历左边界(需要检查是否还有列)if (left <= right) {for (int row = bottom; row >= top; row--) {result.add(matrix[row][left]);}left++; // 左边界右移}}return result;
}

算法步骤详解

示例:3x3矩阵 [[1,2,3],[4,5,6],[7,8,9]]

步骤操作遍历元素边界变化边界状态
初始---top=0, bottom=2, left=0, right=2
1左→右(上边界)1,2,3top++top=1, bottom=2, left=0, right=2
2上→下(右边界)6,9right–top=1, bottom=2, left=0, right=1
3右→左(下边界)8,7bottom–top=1, bottom=1, left=0, right=1
4下→上(左边界)4left++top=1, bottom=1, left=1, right=1
5左→右(上边界)5top++top=2, bottom=1, left=1, right=1
结束top > bottom--循环结束

最终结果:[1,2,3,6,9,8,7,4,5]

边界处理的关键点

1. 为什么步骤3和4需要额外判断?

// 步骤3:从右到左遍历下边界
if (top <= bottom) {  // 检查是否还有行for (int col = right; col >= left; col--) {result.add(matrix[bottom][col]);}bottom--;
}// 步骤4:从下到上遍历左边界  
if (left <= right) {  // 检查是否还有列for (int row = bottom; row >= top; row--) {result.add(matrix[row][left]);}left++;
}

原因:避免重复遍历

2. 边界情况分析

单行矩阵:[[1,2,3,4,5]]
步骤1:1,2,3,4,5 (left→right)
步骤2:无元素 (top=1, bottom=0, 不满足top<=bottom)
结果:[1,2,3,4,5] ✅
单列矩阵:[[1],[2],[3]]
步骤1:1 (left→right)
步骤2:2,3 (top→bottom)  
步骤3:跳过 (top>bottom)
步骤4:跳过 (left>right)
结果:[1,2,3] ✅
2x2矩阵:[[1,2],[3,4]]
步骤1:1,2 (top=0→1)
步骤2:4 (right=1→0)
步骤3:3 (bottom=1→0, 满足top<=bottom)
步骤4:跳过 (left>right)
结果:[1,2,4,3] ✅

可视化理解

边界收缩过程

初始状态:
top=0    ┌─────────┐
left=0 → │ 1  2  3 │ ← right=2│ 4  5  6 ││ 7  8  9 │└─────────┘bottom=2第1步后:
top=1    ┌─────────┐
left=0 → │ █  █  █ ││ 4  5  6 │ ← right=2│ 7  8  9 │└─────────┘bottom=2第2步后:
top=1    ┌─────────┐
left=0 → │ █  █  █ ││ 4  5  █ │ ← right=1│ 7  8  █ │└─────────┘bottom=2第3步后:
top=1    ┌─────────┐
left=0 → │ █  █  █ ││ 4  5  █ │ ← right=1│ █  █  █ │└─────────┘bottom=1第4步后:
top=1    ┌─────────┐
left=1 → │ █  █  █ ││ █  5  █ │ ← right=1│ █  █  █ │└─────────┘bottom=1

在这里插入图片描述

复杂度分析

  • 时间复杂度:O(m×n)
    • 每个元素恰好被访问一次
  • 空间复杂度:O(1)
    • 只使用了常数个变量,不考虑结果数组

常见错误

1. 忘记边界检查

// 错误:可能重复遍历
for (int col = right; col >= left; col--) {result.add(matrix[bottom][col]);
}// 正确:需要检查
if (top <= bottom) {for (int col = right; col >= left; col--) {result.add(matrix[bottom][col]);}
}

2. 边界更新顺序错误

// 错误:先更新边界再遍历
top++;
for (int col = left; col <= right; col++) {result.add(matrix[top][col]);
}// 正确:先遍历再更新边界
for (int col = left; col <= right; col++) {result.add(matrix[top][col]);
}
top++;

总结

螺旋矩阵算法的核心是:

  1. 四边界控制:top、bottom、left、right
  2. 顺时针遍历:右→下→左→上
  3. 边界收缩:每完成一个方向就收缩对应边界
  4. 重复检查:避免在单行/单列情况下重复遍历

这是一个非常经典的模拟算法,考察边界处理和循环控制能力!

http://www.xdnf.cn/news/1397755.html

相关文章:

  • MySQL數據庫開發教學(四) 後端與數據庫的交互
  • 【Docker】Docker初识
  • 医院排班|医护人员排班系统|基于springboot医护人员排班系统设计与实现(源码+数据库+文档)
  • flink中 Lookup Join和Interval Join和Regular Join使用场景与对比
  • HTML 核心元素实战:超链接、iframe 框架与 form 表单全面解析
  • Java类加载与JVM详解:从基础到双亲委托机制
  • 基于 Kubernetes 的 Ollama DeepSeek-R1 模型部署
  • Oracle 数据库性能调优:从瓶颈诊断到精准优化之道
  • Zynq开发实践(FPGA之输入、输出整合)
  • K8s卷机制:数据持久化与共享
  • 【机器学习基础】机器学习中的容量、欠拟合与过拟合:理论基础与实践指南
  • 【高级机器学习】 4. 假设复杂度与泛化理论详解
  • HiFi-GAN模型代码分析
  • 理解JVM
  • web渗透ASP.NET(Webform)反序列化漏洞
  • psql介绍(PostgreSQL命令行工具)(pgAdmin内置、DBeaver、Azure Data Studio)数据库命令行工具
  • 【OpenGL】LearnOpenGL学习笔记17 - Cubemap、Skybox、环境映射(反射、折射)
  • sql简单练习——随笔记
  • 打工人日报#20250830
  • 鸿蒙ArkUI 基础篇-12-List/ListItem-界面布局案例歌曲列表
  • 音视频学习(六十二):H264中的SEI
  • [字幕处理]一种使用AI翻译mkv视频字幕操作流程 飞牛
  • 【Blender】二次元人物制作【一】:二次元角色头部建模
  • Java的Optional实现优雅判空新体验【最佳实践】
  • 【已解决】could not read Username for ‘https://x.x.x‘: No such device or address
  • 算法(③二叉树)
  • leetcode算法刷题的第二十二天
  • DVWA靶场通关笔记-文件包含(Impossible级别)
  • 数据治理进阶——解读数据治理体系基础知识【附全文阅读】
  • 【DreamCamera2】相机应用修改成横屏后常见问题解决方案