题目描述
给你一个 m
行 n
列的矩阵 matrix
,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 10
-100 <= matrix[i][j] <= 100
题目作答
解决这个问题的核心思想是按层模拟。我们可以把矩阵想象成一个洋葱,从最外层开始,一层一层地向内“剥”,依次读取每一层的元素。
为了实现这一点,我们使用四个变量来定义当前遍历层的边界:
top:指向当前层的最顶行的行号。
bottom:指向当前层的最底行的行号。
left:指向当前层的最左列的列号。
right:指向当前层的最右列的列号。
整个遍历过程在一个循环中进行,循环的条件是 left <= right 并且 top <= bottom,这确保了边界内部仍然有元素可以遍历。在每一轮循环中,我们按顺时针顺序走完当前层的一圈:
从左到右:遍历上边界(top行),从 left 列到 right 列,将元素加入结果列表。完成之后,top 行已经被遍历完毕,所以我们将 top 加一,收缩上边界。
从上到下:遍历右边界(right列),从新的 top 行到 bottom 行。完成之后,right 列也被遍历完毕,所以我们将 right 减一,收缩右边界。
从右到左:遍历下边界(bottom行),从新的 right 列到 left 列。完成之后,bottom 行也处理完毕,所以 bottom 减一,收缩下边界。
从下到上:遍历左边界(left列),从新的 bottom 行到 top 行。完成之后,left 列也处理完毕,所以 left 加一,收缩左边界。
这个过程会不断重复,边界不断向内收缩,直到它们交错(left > right 或 top > bottom),此时所有元素都已被遍历。需要注意的是,在第3步和第4步执行前,要检查边界是否依然有效,以防止在处理只有一行或一列的矩阵时重复添加元素。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if (matrix.empty() || matrix[0].empty()) {
return {};
}
int m = matrix.size();
int n = matrix[0].size();
vector<int> result;
// 定义四个边界
int top = 0, bottom = m - 1, left = 0, right = n - 1;
while (left <= right && top <= bottom) {
// 1. 从左到右遍历上边界
for (int j = left; j <= right; ++j) {
result.push_back(matrix[top][j]);
}
top++; // 收缩上边界
// 2. 从上到下遍历右边界
for (int i = top; i <= bottom; ++i) {
result.push_back(matrix[i][right]);
}
right--; // 收缩右边界
// 检查边界是否依然有效,防止重复
if (top <= bottom) {
// 3. 从右到左遍历下边界
for (int j = right; j >= left; --j) {
result.push_back(matrix[bottom][j]);
}
bottom--; // 收缩下边界
}
// 检查边界是否依然有效,防止重复
if (left <= right) {
// 4. 从下到上遍历左边界
for (int i = bottom; i >= top; --i) {
result.push_back(matrix[i][left]);
}
left++; // 收缩左边界
}
}
return result;
}
};