spiralOrder的核心是四边界收缩法:用up、right、down、left控制范围,每走完一方向即收缩对应边界,并在每次循环前检查up>down或left>right以避免越界、重复与漏项。

spiralOrder 的核心不是“怎么遍历”,而是“怎么不越界、不重复、不漏项”。最稳妥的做法是用四边界收缩法,而不是方向数组 + visited 辅助数组——后者在 C++ 中容易因内存访问越界或初始化疏漏出错。
用上下左右四个变量控制边界,边走边缩
这是 C++ 实现中最常用、最易调试的写法。关键在于每次走完一个方向后立刻收缩对应边界,并在进入下一轮前检查是否越界。
-
up表示当前要处理的最上行索引,向右走完第一行后执行up++ -
right表示当前最右列索引,向下走完最后一列后执行right-- -
down表示当前最下行索引,向左走完最后一行后执行down-- -
left表示当前最左列索引,向上走完第一列后执行left++ - 每次 for 循环前都加
if (up > down || left > right)判断,避免空行/空列导致重复或崩溃
注意 for 循环终止条件里的“等号”和边界更新顺序
比如向右走:从 left 到 right(含),走完后 up 才加 1;但紧接着向下走时,起始行是 up(已更新),终点行是 down(尚未更新)。这个“先用再缩”或“先缩再用”的顺序必须统一,否则会漏掉角落元素或访问非法内存。
- 向右:
for (int j = left; j - 向下:
for (int i = up; i - 向左:
for (int j = right; j >= left; --j) res.push_back(matrix[down][j]); down--; - 向上:
for (int i = down; i >= up; --i) res.push_back(matrix[i][left]); left++;
空矩阵和单行/单列的边界情况必须显式处理
C++ 中 matrix.empty() 或 matrix[0].empty() 可能触发未定义行为,尤其当 matrix 是空 vector 时,matrix[0] 会越界。正确做法是:
- 先判断
matrix.size() == 0 - 再判断
matrix[0].size() == 0(仅在 size > 0 时才安全访问matrix[0]) - 单行时,向下/向上循环不会执行(因为
up > down),但向右/向左仍需覆盖整行;单列同理
不要用 visited 数组模拟方向轮转
虽然逻辑直观,但在 C++ 中隐患明显:
立即学习“C++免费学习笔记(深入)”;
- 二维
vector<vector>></vector>初始化开销大,且容易写成vector<bool>(n, vector<bool>(m))</bool></bool>(类型错配) - 方向数组
dr[4] = {0,1,0,-1}和dc[4] = {1,0,-1,0}需严格对齐,下标越界时未检查就访问matrix[r+dr[idx]][c+dc[idx]]会崩溃 - 判断“下一步是否越界或已访问”需要四次比较,性能不如边界法直接
- 真实项目中,边界法更易嵌入到原地修改、内存受限等场景
up、right、down、left 四个变量在任意中间状态都保持语义清晰——比如某次 down-- 后立即发生 up > down,后续循环必须彻底跳过,不能靠“运气”绕过。这点在调试时最容易被忽略。



















