原题:剑指 Offer 29. 顺时针打印矩阵
与主站 54 题相同:54. 螺旋矩阵
方法:边界收缩
基本思路:
顺时针打印二维数组的过程分为“从左到右、从上往下、从右到左、从下往上”循环过程。每一次遍历完一整行或一整列之后,就可以对边界进行一次收缩约束。
算法流程:
- 空值处理:当
matrix
为空时,直接返回空列表即可。 - 边界初始化:左边界
l
初始化为0,右边界r
初始化为col
,上边界t初始化为0,下边界b
初始化为row
- 是否打印完毕的标志,边界是否相遇。
打印方向 | 根据边界打印 | 边界向内收缩 | 打印是否完毕 |
---|---|---|---|
从左向右 | 左边界l ,右边界r | 上边界t 加1 | 是否t>b |
从上向下 | 上边界t ,下边界b | 右边界r 减1 | 是否l>r |
从右向左 | 左边界l ,右边界r | 下边界t 减1 | 是否t>b |
从下向上 | 上边界t ,下边界b | 左边界l 加1 | 是否l>r |
复杂度分析:
- 时间复杂度
O(MN)
:M
,N
分别为矩阵行数和列数。 - 空间复杂度
O(1)
: 四个边界l
,r
,t
,b
使用常数大小的 额外 空间(res
为必须使用的空间)。
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> res;
if(matrix.empty()) return res;
int row=matrix.size(),col=matrix[0].size();
int l=0,r=col-1,t=0,b=row-1;
while(true){
for(int i=l;i<=r;i++){
res.push_back(matrix[t][i]);
}
if(++t>b) break;
for(int i=t;i<=b;i++){
res.push_back(matrix[i][r]);
}
if(l>--r) break;
for(int i=r;i>=l;i--){
res.push_back(matrix[b][i]);
}
if(t>--b) break;
for(int i=b;i>=t;i--){
res.push_back(matrix[i][l]);
}
if(++l>r) break;
}
return res;
}
};
自写代码
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if(matrix.empty()) return result;
int row=matrix.size(),col=matrix[0].size();
addOrderData(matrix,0,row-1,0,col-1);
return result;
}
void addOrderData(vector<vector<int>>& matrix,int rowStart,int rowEnd,int colStart,int colEnd){
if((rowStart > rowEnd) || (colStart > colEnd)) return;
int i=rowStart,j=colStart;
while(i==rowStart && j<=colEnd){
result.push_back(matrix[i][j]);
j++;
}
i=rowStart+1,j=colEnd;
if(i > rowEnd) return;
while(i<=rowEnd && j==colEnd){
result.push_back(matrix[i][j]);
i++;
}
i=rowEnd,j=colEnd-1;
if(j < colStart) return;
while(i==rowEnd && j>=colStart){
result.push_back(matrix[i][j]);
j--;
}
i=rowEnd-1,j=colStart;
if(i < rowStart) return;
while(i>=rowStart+1 && j==colStart){
result.push_back(matrix[i][j]);
i--;
}
addOrderData(matrix,rowStart+1,rowEnd-1,colStart+1,colEnd-1);
}
private:
vector<int> result;
};