提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
跟着Carl哥学完了数组篇,螺旋矩阵不涉及什么算法,但是很考验对代码的掌控力和逻辑把握,跟着卡哥学完以后,自己手撕出来这道题太有成就感了。
正文
根据题目可以模拟出顺时针画矩阵的过程:
1、 上行从左到右
2、 右列从上到下
3、 下行从右到左
4、 左列从下到上
再到内部的矩阵,重复这个过程,所以一定要清楚每个过程的边界条件,是左开右闭,还是左闭右开。
即:每一条边拐角的元素,在处理的时候每条边要保持一致。我坚持的是左闭右开原则。
除此以外,1、我们还要清楚要转多少圈才能完整的走完外圈每个元素?
2、中间值怎么处理?
比如:在一个3 * 4的矩阵,我们只需要一圈就能走完外圈的所有元素,在一个5 * 3的矩阵,我们同样只需要一圈就能走完外圈的所有元素,由此可见,需要转多少圈是由最短边来决定的。
可见:当 行 > 列(宽 > 长)时,中间值是一个特殊的中间列;
当 列 > 行(长 > 宽)时,中间值是一个特殊的中间行;
代码
清楚以上几点,就可以手撕出螺旋矩阵的代码了,整体C++代码如下:
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
int m = matrix.size(), n = matrix[0].size(); // 行, 列
if(m == 0 || n == 0) return {};
vector<int> res(m * n); // 一维数组存放结果
int startx = 0, starty = 0; // 每圈的起始位置
int offset = 1; // 每圈循环, 每条边的长度
int loop = min(m, n) / 2; // 外圈圈数
int mid = min(m, n) / 2; // 中间值
int count = 0;
int i, j;
while(loop--){
i = startx;
j = starty;
// 按左闭右开原则转圈
for(; j < n - offset; j++) // 上行从左到右
res[count++] = matrix[startx][j];
for(; i < m - offset; i++) // 右行从上到下
res[count++] = matrix[i][j];
for(; j > starty; j--) // 下行从右到左
res[count++] = matrix[i][j];
for(; i > startx; i--) // 左行从下到上
res[count++] = matrix[i][starty];
startx++;
starty++; // 起始位置+1,第一圈起始位置[0][0],第二圈起始位置[1][1]....
offset++; // 每圈每一条边遍历长度
}
// 中间值的情况,注:此处不能用mid % 2,当行列均为1时,mid % 2 = 0
if(min(m, n) % 2){
if(m > n){ // 宽大于长,中间还剩下一列没有遍历
for(i = mid; i < mid + m - n + 1; i++)
res[count++] = matrix[i][mid];
}
else{ // 长大于宽,中间还剩下一行没有遍历
for(i = mid; i < mid + n - m + 1; i++){
res[count++] = matrix[mid][i];
}
}
}
return res;
}
};
总结
在边界条件多的循环中,一定要先规定好一个原则,然后每次循环都按照这个原则走,才不会越写越乱,如果不按照固定规则来遍历,那就是一进循环深似海。