LeetCode 54. 螺旋矩阵
本节目标
用四条边界表示尚未访问的矩形,按层完成顺时针遍历。
这道题是矩阵解题框架的边界收缩母题。代码看似只是四段循环,真正需要维护的是“尚未访问区域”的精确定义。
题意与约束
给定一个 m × n 矩阵,按照从左到右、从上到下、从右到左、从下到上的顺时针顺序,返回所有元素。
矩阵可能只有一行或一列,因此最后一层未必仍有完整的四条边。
第一反应:记录访问状态
可以从左上角出发,遇到边界或已访问位置就转向,并用额外矩阵标记访问状态。这个方法能做,但状态较多,也没有利用螺旋顺序天然按矩形外圈推进的结构。
四条边界
令 top、bottom、left、right 包围尚未访问的矩形。每轮依次:
- 遍历上边,然后
top下移; - 遍历右边,然后
right左移; - 若仍有剩余行,遍历下边,然后
bottom上移; - 若仍有剩余列,遍历左边,然后
left右移。
循环不变量是:进入每轮时,边界内的矩形恰好由所有未访问元素组成。
后两条边必须先检查边界。如果最后只剩一行,直接遍历下边会重复;只剩一列时同理。
代码实现
两份实现都只维护四个整数边界,不使用访问标记。
- C++
- Python
C++17
#include <vector>
using namespace std;
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> order;
if (matrix.empty() || matrix[0].empty()) {
return order;
}
int top = 0;
int bottom = static_cast<int>(matrix.size()) - 1;
int left = 0;
int right = static_cast<int>(matrix[0].size()) - 1;
while (top <= bottom && left <= right) {
for (int col = left; col <= right; col++) {
order.push_back(matrix[top][col]);
}
top++;
for (int row = top; row <= bottom; row++) {
order.push_back(matrix[row][right]);
}
right--;
if (top <= bottom) {
for (int col = right; col >= left; col--) {
order.push_back(matrix[bottom][col]);
}
bottom--;
}
if (left <= right) {
for (int row = bottom; row >= top; row--) {
order.push_back(matrix[row][left]);
}
left++;
}
}
return order;
}
};
Python 3
class Solution:
def spiralOrder(self, matrix):
if not matrix or not matrix[0]:
return []
order = []
top = 0
bottom = len(matrix) - 1
left = 0
right = len(matrix[0]) - 1
while top <= bottom and left <= right:
for col in range(left, right + 1):
order.append(matrix[top][col])
top += 1
for row in range(top, bottom + 1):
order.append(matrix[row][right])
right -= 1
if top <= bottom:
for col in range(right, left - 1, -1):
order.append(matrix[bottom][col])
bottom -= 1
if left <= right:
for row in range(bottom, top - 1, -1):
order.append(matrix[row][left])
left += 1
return order
复杂度分析
- 时间复杂度:
O(mn),每个元素恰好加入答案一次。 - 空间复杂度:
O(1),不计返回数组,只使用四个边界变量。
易错点
- 遍历下边和左边前不检查剩余边界,重复访问单行或单列。
- 更新边界的时机错误,把刚访问过的边仍视为未处理区域。
- 用固定四段循环处理空矩阵,提前访问
matrix[0]。 - 把坐标的行列含义写反,长方形矩阵才暴露错误。
模式迁移
边界收缩还适用于按层打印、矩阵分圈旋转和生成螺旋矩阵。迁移时不必记忆转向细节,只要持续维护“边界内恰好是未处理区域”,再按题目要求决定每轮访问哪几条边。