首先顺时针打印矩阵,需要通过图解来理解:
上面是一个3 * 3 的矩阵,我们要将其按照顺时针打印,那么打印的结果就是 1 ➡ 2 ➡ 3 ➡ 4 ➡ 5 ➡ 6 ➡ 7 ➡ 8 ➡ 9
我们可以通过模拟的方法来进行顺时针打印矩阵:
1.求出矩阵的左右宽度、上下宽度、左右边线、上下边线
这里求二维矩阵的左右宽度是 矩阵.size() 上下宽度是 矩阵[0].size()
row为矩阵的宽,col为矩阵的高
那么这里的row其实记录的就是矩阵的列数,而col为矩阵的行数
这里左右边线的 c2 就可以定义为矩阵的列数
上下边线的 r2 就可以定义为矩阵的行数
2.需要计算出打印的次数
打印的次数可以通过得到行数和列数中的最小值来判断,通常判断完整的一圈是由两层构成的,因此在判断打印的次数的时候,可以通过除以 2 来判断。
上述判断可以分为两种,其中一种为行数和列数的最小值为偶数时,如上图 1 ,为 2 行 5 列的矩阵,那么打印次数为 2 / 2 = 1,因此打印的次数为 1 次,也就是打印一圈;而当为奇数时,如上图 2 ,为 3 行 4 列的矩阵, 3 / 2 = 1.5, 因此打印完一圈之后还得再加一圈才能全部打印完。
3.限制在计算出来的打印次数中模拟
从左往右打印,起点为 c1 ,终点为 c2 ,打印到 3 ,因为 r1 始终没变,将数据 1、2、3 放入容器中;
从上往下打印,起点为 r1 + 1,因为 3 已经打印过了,因此从 4 开始打印,重点为 r2,期间 c2 始终没变,将数据 4、5 放入容器中;
从右往左打印,起点为 c2 - 1,从 6 开始打印,终点为大于 c1,期间 r2 始终没变,将数据 6 放入容器中;
从下往上打印,起点为 r2 ,终点为大于 r1,从7开始打印,期间 c1 始终没变,将数据 7、8放入容器中;
4.以上为打印完一圈之后,将四条边线缩小
将四条边线缩小范围,这样可以继续遍历打印矩阵,r1 ++, r2 --, c1 ++, c2 --;
将范围缩小之后,可以设置一个范围,用以判断有没有打印完成,通过判断 c1 小于 c2,和r1小于 r2 来判断是否打印完成。
该题的难点是:1.设置四周边线 2.计算打印的次数 3.判断有没有打印完成
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> res;
if(matrix.empty()) return res;
// 定义左右宽度
int row = matrix.size();
// 定义上下宽度
int col = matrix[0].size();
// 定义左右边线
int c1 = 0, c2 = matrix[0].size()-1;
// 定义上下边线
int r1 = 0, r2 = matrix.size()-1;
// 定义打印的次数
int times = min(row, col) % 2 == 0 ? min(row, col) / 2 : min(row, col) / 2 + 1;
// 限制打印次数
for(int i = 0;i < times;i++)
{
// 开始打印
// 从左到右打印
for(int i = c1;i <= c2;i++) res.push_back(matrix[r1][i]);
// 从上往下打印
for(int i = r1+1;i <= r2;i++) res.push_back(matrix[i][c2]);
// 判断有没有打印完
if(r1 < r2 && c1 < c2)
{
// 从右往左打印
for(int i = c2 - 1;i > c1;i--) res.push_back(matrix[r2][i]);
// 从下往上打印
for(int i = r2;i > r1;i--) res.push_back(matrix[i][c1]);
}
r1++;
r2--;
c1++;
c2--;
}
return res;
}
};