题意
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
题解
顺时针打印矩阵的顺序是 “从左向右、从上向下、从右向左、从下向上” 循环。
并且在遍历的时候,我们遵循左闭右闭原则。
考虑设定矩阵的“左、上、右、下”四个边界,模拟以上矩阵遍历顺序。
算法流程:
- 空值处理: 当
matrix
为空时,直接返回空列表[]
即可。 - 初始化: 矩阵 左、右、上、下 四个边界
l
,r
,t
,b
,用于打印的结果列表res
。 - 循环打印: “从左向右、从上向下、从右向左、从下向上” 四个方向循环,每个方向打印中做以下三件事:
- 根据边界打印,即将元素按顺序添加至列表
res
尾部; - 边界向内收缩 1 (代表边界已被打印);
- 判断是否打印完毕(边界是否相遇),若打印完毕则跳出。
- 根据边界打印,即将元素按顺序添加至列表
- 返回值: 返回
res
即可。
打印方向 | 1. 根据边界打印 | 2.边界向内收缩 | 3.是否打印完毕 |
从左向右 | 将 左边界l 到 右边界r 的元素添加到结果res尾部 | 上边界t加1。因为我们下一步要将最右边从上往下的的边的数值加到res尾部了,但是这条边的第一个元素又已经被遍历过了,所以上边界t要加1,防止重复遍历元素(因为我们是左闭右闭原则)。 | 是否
|
从上向下 | 上边界 t ,下边界b | 右边界 r 减 1 | 是否 |
从右向左 | 右边界 r ,左边界l | 下边界 b 减 1 | 是否
|
从下向上 | 下边界 b ,上边界t | 左边界 l 加 1 | 是否
|
C++实现
class Solution
{
public:
vector<int> spiralOrder(vector<vector<int>>& matrix)
{
if(matrix.empty())
return {};//如果矩阵为空,返回空
vector<int> res; //存放结果
res.reserve(matrix.size()*matrix[0].size()); // 预先分配好内存
int l=0; //初始的左边界
int r=matrix[0].size()-1; //初始的右边界
int t=0; //初始的上边界
int b=matrix.size()-1; //初始的下边界
while(true)
{
//遍历矩阵最上面(上边界位置)从左到右(从左边界到有边界的位置)的那条边,遍历时行数是不变的,即上边界不变
for(int i=l;i<=r;++i)
{
res.push_back(matrix[t][i]);
}
//边界收缩,上边界加1,表示上边界这条边已经遍历完毕,并且判断收缩后是否超出下边界,如果超出下边界则表示遍历完毕
if(++t>b)
break;
//遍历矩阵最右边(右边界位置),从上到下的那条边(上边界到下边界位置),遍历时列数(即右边界)不变
for(int i=t;i<=b;++i)
{
res.push_back(matrix[i][r]);
}
//边界收缩,右边界减1,表示最右边(右边界位置)的那条边已经遍历完毕。同时判断右边界收缩后是不是小于左边界了,
//如果小于则表示遍历完毕。
if(--r<l)
break;
//遍历矩阵最下面(下边界位置)的那条边。从右向左遍历,遍历时行数(即下边界位置)不变
for(int i=r;i>=l;--i)
{
res.push_back(matrix[b][i]);
}
//边界收缩,表示下边界位置所处的边遍历完毕,同时下边界减1。下边界收缩后判读是否小于上边界
if(--b<t)
break;
//遍历矩阵最左边的边(左边界位置的边),从下到上遍历。
for(int i=b;i>=t;--i)
{
res.push_back(matrix[i][l]);
}
//边界收缩
if(++l>r)
break;
}
return res;
}
};