尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
LeetCode 每日一题解析:54. Spiral Matrix 螺旋矩阵(剥洋葱法与方向数组法全解)
LeetCode 每日一题解析54. Spiral Matrix 螺旋矩阵剥洋葱法与方向数组法全解【免费下载链接】leetcodeLeetCode Solutions: A Record of My Problem Solving Journey.( leetcode题解记录自己的leetcode解题之路。)项目地址: https://gitcode.com/gh_mirrors/le/leetcode本篇技术指南基于本仓库「每日一题」系列文档 daily/2019-07-29.md 展开完整讲解 LeetCode 54 题「螺旋矩阵Spiral Matrix」的题目背景、两种经典解法的核心思想与 JavaScript 实现并结合仓库源码 daily/answers/54.spiral-matrix.js 给出第三种精简实现。读完本文你将掌握如何通过「边界收缩」与「方向数组」两种思路在 O(m×n) 时间内完成矩阵螺旋遍历并理解其时间复杂度与空间复杂度推导可直接迁移到旋转矩阵、蛇形遍历等同类题目。信息卡片题目LeetCode 54. Spiral Matrix螺旋矩阵分类标签Array数组、Matrix矩阵所属系列本仓库 每日一题 活动2019-07-29 期历史汇总中编号 54.Spiral Matrix核心考点边界收缩、方向模拟、循环终止条件设计题目描述给定一个包含 m × n 个元素的矩阵m 行 n 列请按照顺时针螺旋顺序返回矩阵中的所有元素。示例 1Input: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] Output: [1,2,3,6,9,8,7,4,5]示例 2Input: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] Output: [1,2,3,4,8,12,11,10,9,5,6,7]从示例可以直观看到遍历顺序先沿第一行从左到右再沿最后一列从上到下然后沿最后一行从右到左再沿第一列从下到上……如此一圈一圈向内收缩直到所有元素被访问完毕。解法一剥洋葱法边界收缩这是最直观、最容易写对的思路原文档将其形象地称为「剥洋葱」——每一圈就像剥掉一层洋葱皮。核心思想一圈一轮row - col - row - col为一次完整的外圈遍历即“向右 → 向下 → 向左 → 向上”四个方向各走一段边界内收每完成一个方向的遍历对应的边界就向内收缩一步。row-col、col-row的切换都伴随读取起始位置的变化1 或 -1结束条件行头大于行尾rowT rowB或列左大于列右colL colR时说明矩阵已被剥完循环终止。以示例 1 的三行三列矩阵为例第一圈向右读[1,2,3]向下读[6,9]向左读[8,7]向上读[4]第二圈只剩中心元素[5]直接向右读入完成得到[1,2,3,6,9,8,7,4,5]。复杂度分析时间复杂度O(m × n)每个元素恰好被访问一次空间复杂度O(1)除结果数组外仅使用四个边界指针。参考实现JavaScript/** * param {number[][]} matrix * return {number[]} */ var spiralOrder function(matrix) { if(matrix.length 0) return []; let rowT 0; // 行顶 let rowB matrix.length - 1; // 行底 let colL 0; // 列左 let colR matrix[0].length - 1; // 列右 let result []; // 顺序是行、列、行、列每次切换读取的初始位置都会变化1(/- 1) while (colL colR rowT rowB) { for (let a colL; a colR; a) { result.push(matrix[rowT][a]); } rowT; for (let b rowT; b rowB; b) { result.push(matrix[b][colR]); } colR--; for (let c colR; c colL rowB rowT; c--) { result.push(matrix[rowB][c]); } rowB--; for (let d rowB; d rowT colR colL; d--) { result.push(matrix[d][colL]); } colL; } return result; };实现要点说明边界变量命名rowT行顶、rowB行底、colL列左、colR列右四次for循环分别对应四个方向每次遍历完成后立即把对应边界向中心收缩一步rowT、colR--、rowB--、colL循环条件colL colR rowT rowB保证了矩阵在只剩一行或一列时也能正确收尾——此时内层的向左、向上循环因边界条件rowB rowT、colR colL而自动跳过不会重复读取元素。解法二方向数组法单个 for 循环 方向切换剥洋葱法虽然直观但代码中有四个几乎对称的for循环略显冗长。原文档给出的第二种思路把四个方向统一抽象为方向向量用同一段循环代码完成全部遍历。核心思想四个方向可以用二维数组表示const dirs [[0, 1], [1, 0], [0, -1], [-1, 0]];分别对应right向右列 1、down向下行 1、left向左列 -1、up向上行 -1。四个方向分成两类水平方向right、left与垂直方向down、up。在两类方向上的最大移动步数分别是水平 n、垂直 m。遍历过程中每当方向切换就把对应类别的最大步数减一逐步缩小移动范围直到 n 0 或 m 0 表示所有元素遍历完毕。以文档中的 3 行 5 列矩阵为例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15对上面矩阵遍历时的操作序列为向右 5 次算上从左侧第一次进入向下 2 次向左 4 次向上 1 次向右 3 次向下 0 次 —— 结束可以看到水平方向right/left的移动极值从 n 开始逐轮递减垂直方向down/up的移动极值从 m-1 开始逐轮递减。两类方向各自的初始最大值是[n, m-1]当n 0 || m 0时元素已全部遍历完。这种写法的优点是把四个方向的遍历合并成一个for循环缺点是while循环轮次变多但整体时间复杂度不变。复杂度分析时间复杂度O(m × n)仍然是每个元素恰好访问一次空间复杂度O(1)。参考实现JavaScript/** * param {number[][]} matrix * return {number[]} * 一个for循环,但while变多了 */ var spiralOrder function(matrix) { if(matrix.length 0) return []; let m matrix.length; let n matrix[0].length; let result []; const dirs [[0, 1], [1, 0], [0, -1], [-1, 0]] // 控制方向的数组 // 元素坐标row,col; let row 0; let col -1; let steps [n, m-1] let dir 0; // 初始方向 while(steps[dir%2]) { for(let i 0; i steps[dir%2]; i) { // 方向的改变的效果row/col能增能减 row dirs[dir][0]; col dirs[dir][1]; result.push(matrix[row][col]) } steps[dir%2]--; // 移动极值缩小 dir (dir1)%4; // 方向改变 } return result; };实现要点说明初始坐标设为row 0, col -1目的是让第一步col 1恰好落在矩阵左上角matrix[0][0]steps[dir % 2]用方向的奇偶性区分水平与垂直dir 0right与dir 2left时dir % 2 0取水平步数 ndir 1down与dir 3up时取垂直步数 m-1每次方向切换后steps[dir % 2]--缩小对应类别的移动极值dir (dir 1) % 4让方向按 right → down → left → up → right 循环while(steps[dir % 2])在步数降为 0 时退出此时矩阵已遍历完毕。解法三仓库源码中的精简实现边遍历边判停除了原文档中的两种写法本仓库的每日一题答案文件 daily/answers/54.spiral-matrix.js 中保存了第三种实现。它在剥洋葱思想的基础上把循环条件改为while(true)在每完成一个方向的遍历后立即检查边界是否越界并break代码更紧凑var spiralOrder function(matrix) { const res []; if (matrix.length 0) return res; let top 0; let bottom matrix.length - 1; let left 0; let right matrix[0].length - 1; while (true) { for (let i left; i right; i) res.push(matrix[top][i]); top; if (top bottom) break; for (let i top; i bottom; i) res.push(matrix[i][right]); right--; if (left right) break; for (let i right; i left; i--) res.push(matrix[bottom][i]); bottom--; if (top bottom) break; for (let i bottom; i top; i--) res.push(matrix[i][left]); left; if (left right) break; } return res; };这个版本与解法一相比有三个不同点边界命名更简洁top/bottom/left/right循环条件改为while(true)退出完全依赖四个方向内的break判断每次边界收缩后立即检查top bottom或left right逻辑上更接近「剥完一层就判断是否结束」的自然直觉也不需要在反向遍历的for循环里追加额外边界条件。该文件头部保留了题解来源注释LeetCode 讨论区一篇名为 Clean Java readable human-friendly code 的帖子可供参考比对不同语言的同思路实现。其时间复杂度同样为 O(m × n)空间复杂度 O(1)。三种解法对比与选择建议对比维度解法一剥洋葱法解法二方向数组法解法三精简判停法核心思路四边界逐方向收缩方向向量 步数递减边界收缩 立即判停循环结构1 个 while 4 个 forwhile 单个 for轮次变多while(true) 4 个 for代码可读性高四个方向清晰对称中需要理解方向数组与步数递减高结构最紧凑出错风险点反向遍历需追加边界判断初始坐标与步数初值易错四个 break 位置必须准确时空复杂度O(m×n) / O(1)O(m×n) / O(1)O(m×n) / O(1)三种解法的时间复杂度、空间复杂度完全一致差异只体现在代码组织方式上面试首推解法一边界收缩思路与「剥洋葱」的直观比喻完全对应最不容易写错也最容易向面试官讲清逻辑解法二适合理解遍历本质方向数组把「方向」这一抽象概念具体化为数据对后续处理旋转矩阵、蛇形填数等问题有启发意义解法三适合追求简洁仓库源码中的实现已通过实战检验可作为日常刷题的参考范式。延伸与进阶螺旋遍历在矩阵类题目中属于基础操作掌握后可以进一步挑战旋转矩阵如 LeetCode 48. Rotate Image同样涉及边界收缩与坐标映射仓库中的题解 problems/48.rotate-image.md 与配套绘图 assets/drawio/48.rotate-image.drawio 可对照学习螺旋矩阵 IILeetCode 59把「读」改为「写」用同一套边界收缩逻辑反向填充矩阵检验对思路的掌握程度本仓库为本题维护了可视化绘图文件 assets/drawio/54.spiral-matrix.drawio可用 draw.io 打开查看螺旋遍历的边界变化过程辅助理解「剥洋葱」每一圈的收缩细节。小结本文围绕 LeetCode 54 题「螺旋矩阵」给出了三种 JavaScript 实现基于四边界收缩的剥洋葱法、基于方向数组的步数递减法以及仓库答案文件中保存的精简判停版。三者在时间复杂度 O(m×n) 与空间复杂度 O(1) 上保持一致区别仅在于循环组织方式。建议以「剥洋葱」思路作为首选模板配合方向数组理解遍历本质即可稳定应对螺旋遍历及其变体题目。【免费下载链接】leetcodeLeetCode Solutions: A Record of My Problem Solving Journey.( leetcode题解记录自己的leetcode解题之路。)项目地址: https://gitcode.com/gh_mirrors/le/leetcode创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

降ai提示词大全免费分享!论文降AI率5类指令怎么用,AIGC检测标红段实测对照,重复率不反涨!

降ai提示词大全免费分享!论文降AI率5类指令怎么用,AIGC检测标红段实测对照,重复率不反涨!

降ai提示词大全免费分享!论文降AI率5类指令怎么用,AIGC检测标红段实测对照,重复率不反涨! 导师只给了两周,行政管理的学妹把万方报告截图发我,第四章问题分析整章标红,8200字的论文初检AI率49%…

📅 2026/9/18 23:06:38
Hyperresearch Levers完全指南:teach、survey、analyze、advocate四种报告语气切换

Hyperresearch Levers完全指南:teach、survey、analyze、advocate四种报告语气切换

Hyperresearch Levers完全指南:teach、survey、analyze、advocate四种报告语气切换 【免费下载链接】hyperresearch Agent-driven research knowledge base. Agents collect, search, and synthesize web research into a persistent, searchable wiki. 项目地址:…

📅 2026/9/18 23:06:38
Roc 嵌套关联类型前向引用解析:从快照测试剖析 nominal 类型块的作用域与规范化语义

Roc 嵌套关联类型前向引用解析:从快照测试剖析 nominal 类型块的作用域与规范化语义

Roc 嵌套关联类型前向引用解析:从快照测试剖析 nominal 类型块的作用域与规范化语义 【免费下载链接】roc A fast, friendly, functional language. 项目地址: https://gitcode.com/GitHub_Trending/ro/roc 本篇文章以 Roc 编译器测试仓库中的快照用例 canon…

📅 2026/9/18 23:06:38
MORE NEWS

更多资讯

📰

Unity实时画面采集与RTMP推流实战:RenderTexture+FFmpeg方案详解

搞过Unity实时画面采集的人应该都有同感:引擎自带的Camera输出到屏幕容易,但一旦涉及“把画面送到外部去”,比如录制成文件、推成直播流,能查到的完整资料就少得可怜。Unity官方对录屏、推流这块基本处于“你自己看着办”的状态&a…

📰

React Native中的Hermes配置管理:oh-my-hermes插件化实践

做React Native开发这些年,Hermes引擎基本成了绕不开的标配。但说实话,项目里的Hermes配置一直挺乱的——初始化参数散在gradle、metro配置、Java代码里,每次新建工程都要翻文档重新查一遍,不同版本的RN配置写法还不一样&#xff…

📰

RealSense SDK macOS 安装:3 步快速编译 librealsense,跑通第一帧深度流

RealSense SDK macOS 安装:3 步快速编译 librealsense,跑通第一帧深度流 【免费下载链接】librealsense RealSense SDK 项目地址: https://gitcode.com/GitHub_Trending/li/librealsense 围绕 RealSense SDK macOS 安装,本文带你把相机…

📰

k-skill 项目实战:public-restroom-nearby 技能如何实现「附近公共卫生间查找」

k-skill 项目实战:public-restroom-nearby 技能如何实现「附近公共卫生间查找」 【免费下载链接】k-skill 한국인을 위한 스킬 모음집 - 에이전트를 한국인으로 项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill 导读 public-restroom-nearby 是 …

📰

Fluent Bit Kubernetes 过滤器运行时测试指南:基于伪 Kubernetes API Server 的元数据注入验证

Fluent Bit Kubernetes 过滤器运行时测试指南:基于伪 Kubernetes API Server 的元数据注入验证 【免费下载链接】fluent-bit Fast and Lightweight Logs, Metrics and Traces processor for Linux, BSD, OSX and Windows 项目地址: https://gitcode.com/GitHub_Tr…

📰

用XinServer实现项目进度自动化管理:从任务编排到CI/CD联动

开头:从一次差点翻车的进度会说起上季度我们团队负责一个边缘业务系统的升级,排期只有六周,需求却拆出了四十多个子任务。当时我心里其实没底,因为团队里一半人同时要处理线上问题,另一半人对新业务逻辑不熟。开进度会…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬