螺旋矩阵:无人机如何一圈圈扫描仓库?
Drone Spiral Scan · 边界收缩不是找路,不是 DP,而是维护一个不断缩小的「未扫描矩形」。 四个边界变量框住剩余区域,无人机按 top → right → bottom → left 顺时针扫完一圈,再把边界向内推。
四个边界变量 top=0 · bottom=2 · left=0 · right=3 不是方向,而是还没访问区域的边界。每扫完一条边,就把这条边从剩余矩形里删掉(向内收缩)。
仓库待扫描
这是一块 m×n 的货架矩阵。无人机要从外圈开始,顺时针螺旋扫描每个编号,并把结果依次送入右侧传送带。
目标不是找路径,而是维护一个不断缩小的「未扫描矩形」,按 top → right → bottom → left 四条边依次访问。
仓库扫描区
3×4 · 未扫描矩形 [0..2] × [0..3]输出传送带 · ans
len = 0每扫描一格,数值从仓库推入传送带,顺序即螺旋遍历序。
状态变量
伪代码 · 逐行高亮
spiralOrder1function spiralOrder(matrix):2 top = 03 bottom = matrix.length - 14 left = 05 right = matrix[0].length - 16 ans = []78 while top <= bottom and left <= right:9 for col from left to right:10 ans.push(matrix[top][col])11 top++1213 for row from top to bottom:14 ans.push(matrix[row][right])15 right--1617 if top <= bottom:18 for col from right down to left:19 ans.push(matrix[bottom][col])20 bottom--2122 if left <= right:23 for row from bottom down to top:24 ans.push(matrix[row][left])25 left++2627 return ans
四边界心智模型
初始:top=0, bottom=m-1, left=0, right=n-1
- top上边界行号0
- bottom下边界行号2
- left左边界列号0
- right右边界列号3
为什么要检查边界?
bottom 和 left 不是「永远要扫」——它们只在剩余矩形还有高度/宽度时才存在。 单行或单列时,某条边扫完后边界会交叉,再扫就会重复访问同一行或列。
反例 1 · 单行矩阵 [[1,2,3,4]]
扫完 top 行后 top++,此时 top > bottom。若仍扫 bottom 行,会再次访问同一行。所以扫 bottom 前必须判断 top <= bottom。
关键检查:if (top <= bottom)
反例 2 · 单列矩阵 [[1],[2],[3]]
扫完 right 列后 right--,此时 left > right。若仍扫 left 列,会再次访问同一列。所以扫 left 前必须判断 left <= right。
关键检查:if (left <= right)
步骤轨迹
| # | 阶段 | 说明 | ans.len |
|---|---|---|---|
| 1 | 概览 | 仓库待扫描 | 0 |
| 2 | 初始化 | 初始化四边界 | 0 |
| 3 | 扫上边 | 第 1 圈 · 扫上边 | 0 |
| 4 | 扫描格 | 访问 (0,0) = 1 | 1 |
| 5 | 扫描格 | 访问 (0,1) = 2 | 2 |
| 6 | 扫描格 | 访问 (0,2) = 3 | 3 |
| 7 | 扫描格 | 访问 (0,3) = 4 | 4 |
| 8 | 收缩 top | 上边扫完 · top 向内收缩 | 4 |
| 9 | 扫右边 | 扫右边 | 4 |
| 10 | 扫描格 | 访问 (1,3) = 8 | 5 |
| 11 | 扫描格 | 访问 (2,3) = 12 | 6 |
| 12 | 收缩 right | 右边扫完 · right 向内收缩 | 6 |
| 13 | 检查 bottom | 检查能否扫下边 | 6 |
| 14 | 扫下边 | 扫下边 | 6 |
| 15 | 扫描格 | 访问 (2,2) = 11 | 7 |
| 16 | 扫描格 | 访问 (2,1) = 10 | 8 |
| 17 | 扫描格 | 访问 (2,0) = 9 | 9 |
| 18 | 收缩 bottom | 下边扫完 · bottom 向内收缩 | 9 |
| 19 | 检查 left | 检查能否扫左边 | 9 |
| 20 | 扫左边 | 扫左边 | 9 |
| 21 | 扫描格 | 访问 (1,0) = 5 | 10 |
| 22 | 收缩 left | 左边扫完 · left 向内收缩 | 10 |
| 23 | 内圈 | 进入内圈 | 10 |
| 24 | 扫上边 | 第 2 圈 · 扫上边 | 10 |
| 25 | 扫描格 | 访问 (1,1) = 6 | 11 |
| 26 | 扫描格 | 访问 (1,2) = 7 | 12 |
| 27 | 收缩 top | 上边扫完 · top 向内收缩 | 12 |
| 28 | 扫右边 | 扫右边 | 12 |
| 29 | 收缩 right | 右边扫完 · right 向内收缩 | 12 |
| 30 | 检查 bottom | 检查能否扫下边 | 12 |
| 31 | 跳过 bottom | 跳过下边扫描 | 12 |
| 32 | 完成 | 扫描完成 | 12 |
面试回答模板
我用四个边界 top / bottom / left / right 表示当前还没访问的矩形区域。每轮依次访问上边、右边、下边、左边。访问完一条边后,把对应边界向内收缩。为了避免单行或单列时重复访问,下边和左边访问前要检查 top <= bottom、left <= right。 每个元素只访问一次,所以时间复杂度是 O(m×n),除了结果数组外只用常数额外空间。