1. 题目说了什么
LeetCode 885 这道题,我最初刷到的时候愣了一下,因为它的名字叫 Spiral Matrix III,但和前面两道螺旋矩阵的玩法完全不同。前两题是给你一个完整矩阵,让你把它按螺旋顺序“读”出来;这一题是反过来——给你矩阵的行列数 rows 和 cols,再给你一个起始坐标 (rStart, cStart),然后模拟一个人站在这个位置,按顺时针螺旋的方式走,每经过一个格子就记下坐标,直到把整个矩阵的所有格子都走完。
这个题最反直觉的地方在于:矩阵外的区域也要“走”,只是不记录。因为螺旋线是连续的,从矩阵内部出发后,会不断向外扩张绕圈,中途必然路过矩阵外的空白区域,但只有落在矩阵范围内的坐标才被收入答案。换句话说,你要模拟的是一个不存在的“无限矩阵”上的螺旋路径,然后把落在给定矩形内的点摘出来。
适合谁来看这道题?如果你刚刷完数组、矩阵类的模拟题,或者正在准备面试中常见的“方向行走”类题目,这道题是很好的进阶训练。它不像 BFS/DFS 那样需要复杂数据结构,核心就是“规律 + 模拟”,但非常考验你对循环边界和方向控制的敏感度,写不好就容易出现索引越界、死循环、重复添加这一类问题。
我个人刷题时有个习惯:遇到模拟题,一定先动手画一遍小矩阵,把行走轨迹画出来,再抽象成代码。这道题尤其适合这么干,因为它的步长规律非常规整,画一遍基本就通透了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心思路拆解
2.1 为什么不能用传统螺旋矩阵的“边界收缩”法
做过第 54 题 Spiral Matrix 的同学应该很熟悉“边界收缩”的思路:维护上、下、左、右四个边界,每次沿着边界走,走完一圈就把某条边界往里缩一格,直到上边界大于下边界或左边界大于右边界。
但这个思路套到 885 题上会很别扭。原因是第 54 题的螺旋中心一定在矩阵内部,且矩阵本身是完整的矩形;而 885 题的起点 (rStart, cStart) 可能在矩阵内任意位置,螺旋的“中心”并不是矩阵中心,甚至起点可能在矩阵边缘附近。如果你强行用边界收缩法,你会发现“当前这一圈”和矩阵的实际边界完全对不上,收缩逻辑很难写。
更关键的一点:885 题要求我们在矩阵外部也继续走,但边界收缩法的前提是“当前圈完全在矩阵内”,一旦走到矩阵外的区域,这个前提就被打破了。所以不用惦记边界收缩,直接换思路。
2.2 抓住螺旋行走的步长规律
仔细看螺旋路径的步长变化:从起点出发,先向右走 1 步,然后转向向下走 1 步,再向左走 2 步,向上走 2 步,向右走 3 步,向下走 3 步……规律非常清晰:
- 方向顺序固定为:右、下、左、上,四个方向循环。
- 步长是 1、1、2、2、3、3、4、4……也就是每个步长连续使用两次后,步长加 1。
为什么要这样?因为螺旋是一圈一圈向外扩的:第一圈从中心出发,走到右、下时各走 1 步;然后向左、上各走 2 步回到中心附近的上方,接着向右走 3 步、向下走 3 步,就完成了第二圈……每绕一圈,半径增加 1,所以步长会在每两个方向后增加 1。
这个规律是整个算法的基石。你不需要关心当前走到了第几圈,只需要维护一个变量 step,表示当前这一段的步长;再用一个变量 count,记录当前步长已经使用了几次。每走完一段(即 step 步之后),count 加 1;当 count 等于 2 时,step 加 1,count 清零,同时方向切换到下一个。
坐标更新就更直接了:用方向数组 dr = [0, 1, 0, -1] 和 dc = [1, 0, -1, 0],分别对应右、下、左、上。每一小步执行 r += dr[dirIndex]; c += dc[dirIndex],然后检查 (r, c) 是否在行号 0 到 rows-1、列号 0 到 cols-1 的范围内,如果在,就加入答案。
