54. 螺旋矩阵(中等)

Blind 75 › 54. 螺旋矩阵(中等) (第 2 章)
文章工具

题目

给定一个 m 行 n 列的整数矩阵,从左上角出发:先向右走到右边界,再向下、向左、向上,贴着尚未访问的区域一圈一圈往里走,按访问顺序返回其中的所有元素。

自造示例:[[1,2,3],[4,5,6],[7,8,9],[10,11,12]] → [1,2,3,6,9,12,11,10,7,4,5,8]。

约束:m ≥ 1,n ≥ 1;元素值范围 -100 ~ 100。

思路

一句话:不要一个格子一个格子地“试走”,而是把螺旋看成一圈一圈剥掉外层的边,用四条边界表示当前未访问的矩形。

最直白的做法是“方向模拟”:定义上、右、下、左四个方向,每次走下一步前都判断“下一格是否越界、是否已经访问过”。这样能写,但需要一张 m × n 的访问表,且转向、停止条件都容易写错。

关键观察:螺旋的每一圈都是当前矩形的四条边——上边从左到右、右边从上到下、下边从右到左、左边从下到上。每剥完一条边,就把对应的边界向里收缩一格,剩下的仍是矩形,于是可以重复同样操作。

因此不需要维护“下一步怎么走”,只需要维护 top / bottom / left / right 四条边界,逐步收缩即可。唯一要小心的是:某些圈只剩一行或一列时,要把“下边、左边”的遍历保护起来,避免重复收录。

解法

维护四个边界 top, bottom, left, right,循环处理:

  1. 从左到右走 top 行,然后 top++。
  2. 从上到下走 right 列,然后 right--。
  3. 若 top ≤ bottom:从右到左走 bottom 行,然后 bottom--。
  4. 若 left ≤ right:从下到上走 left 列,然后 left++。

以自造示例看过程:

当前边界本轮收集收缩后边界
top=0, bottom=3, left=0, right=2上边 1,2,3;右边 6,9,12;下边 11,10;左边 7,4top=1, bottom=2, left=1, right=1
top=1, bottom=2, left=1, right=1上边 5;右边 8top=2, bottom=2, left=1, right=0
top=2, bottom=2, left=1, right=0已无未访问元素,循环结束—

最终结果即 [1,2,3,6,9,12,11,10,7,4,5,8]。

下图把上面 4 个步骤串成流程,并逐步演示:

54. 螺旋矩阵(中等) 解法步骤流程图
图① 解法步骤流程图(共 4 步)。
54. 螺旋矩阵(中等) 按步骤逐步执行的动画
动图② 按步骤依次推进(循环播放)。

C++

C++ 片段需补全 main() 函数才能运行在实训台打开 →
class Solution {
public:
 vector<int> spiralOrder(vector<vector<int>>& matrix) {
 int top = 0, bottom = matrix.size() - 1;
 int left = 0, right = matrix[0].size() - 1;
 vector<int> ans;  while (top <= bottom && left <= right) {
 // 上边:left → right
 for (int j = left; j <= right; ++j) {
 ans.push_back(matrix[top][j]);
 }
 ++top;  // 右边:top → bottom
 for (int i = top; i <= bottom; ++i) {
 ans.push_back(matrix[i][right]);
 }
 --right;  // 只剩一行时,下边不能再走,否则会重复
 if (top <= bottom) {
 for (int j = right; j >= left; --j) {

🔒

本篇为付费内容

您已阅读试读部分,购买后即可解锁全文。

⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。