D

当前:LC54 · 螺旋矩阵:无人机螺旋扫描仓库 · 首次出现于 Day 53 · 路径:顶栏「56天打卡」→ 点击 LC 题号 → 逐题动画

LC54

螺旋矩阵:无人机如何一圈圈扫描仓库?

Drone Spiral Scan · 边界收缩

不是找路,不是 DP,而是维护一个不断缩小的「未扫描矩形」。 四个边界变量框住剩余区域,无人机按 top → right → bottom → left 顺时针扫完一圈,再把边界向内推。

输入 · 3×4 仓库矩阵
[[1,2,3,4],[5,6,7,8],[9,10,11,12]]
目标输出
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
螺旋扫描序 → 传送带 ans

四个边界变量 top=0 · bottom=2 · left=0 · right=3 不是方向,而是还没访问区域的边界。每扫完一条边,就把这条边从剩余矩形里删掉(向内收缩)。

样例切换期望 [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7]
Step 1/32 · 概览

仓库待扫描

这是一块 m×n 的货架矩阵。无人机要从外圈开始,顺时针螺旋扫描每个编号,并把结果依次送入右侧传送带。

目标不是找路径,而是维护一个不断缩小的「未扫描矩形」,按 top → right → bottom → left 四条边依次访问。

仓库扫描区

3×4 · 未扫描矩形 [0..2] × [0..3]
top wall = 0
bottom wall = 2
left wall = 0
right wall = 3
1
2
3
4
5
6
7
8
9
10
11
12
当前位置 (-1, -1) · 无活跃扫描点

输出传送带 · ans

len = 0
等待第一个扫描结果…

每扫描一格,数值从仓库推入传送带,顺序即螺旋遍历序。

状态变量

top = 0bottom = 2left = 0right = 3direction = ans.len = 0

伪代码 · 逐行高亮

spiralOrder
1function spiralOrder(matrix):
2 top = 0
3 bottom = matrix.length - 1
4 left = 0
5 right = matrix[0].length - 1
6 ans = []
7
8 while top <= bottom and left <= right:
9 for col from left to right:
10 ans.push(matrix[top][col])
11 top++
12
13 for row from top to bottom:
14 ans.push(matrix[row][right])
15 right--
16
17 if top <= bottom:
18 for col from right down to left:
19 ans.push(matrix[bottom][col])
20 bottom--
21
22 if left <= right:
23 for row from bottom down to top:
24 ans.push(matrix[row][left])
25 left++
26
27 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]]

1
2
3
4
错误路线[1, 2, 3, 4, 4, 3, 2, 1] · 重复!
正确路线[1, 2, 3, 4]

扫完 top 行后 top++,此时 top > bottom。若仍扫 bottom 行,会再次访问同一行。所以扫 bottom 前必须判断 top <= bottom。

关键检查:if (top <= bottom)

反例 2 · 单列矩阵 [[1],[2],[3]]

1
2
3
错误路线[1, 2, 3, 3, 2, 1] · 重复!
正确路线[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) = 11
5扫描格访问 (0,1) = 22
6扫描格访问 (0,2) = 33
7扫描格访问 (0,3) = 44
8收缩 top上边扫完 · top 向内收缩4
9扫右边扫右边4
10扫描格访问 (1,3) = 85
11扫描格访问 (2,3) = 126
12收缩 right右边扫完 · right 向内收缩6
13检查 bottom检查能否扫下边6
14扫下边扫下边6
15扫描格访问 (2,2) = 117
16扫描格访问 (2,1) = 108
17扫描格访问 (2,0) = 99
18收缩 bottom下边扫完 · bottom 向内收缩9
19检查 left检查能否扫左边9
20扫左边扫左边9
21扫描格访问 (1,0) = 510
22收缩 left左边扫完 · left 向内收缩10
23内圈进入内圈10
24扫上边第 2 圈 · 扫上边10
25扫描格访问 (1,1) = 611
26扫描格访问 (1,2) = 712
27收缩 top上边扫完 · top 向内收缩12
28扫右边扫右边12
29收缩 right右边扫完 · right 向内收缩12
30检查 bottom检查能否扫下边12
31跳过 bottom跳过下边扫描12
32完成扫描完成12

面试回答模板

我用四个边界 top / bottom / left / right 表示当前还没访问的矩形区域。每轮依次访问上边、右边、下边、左边。访问完一条边后,把对应边界向内收缩。为了避免单行或单列时重复访问,下边和左边访问前要检查 top <= bottomleft <= right。 每个元素只访问一次,所以时间复杂度是 O(m×n),除了结果数组外只用常数额外空间。