难度中等1301
给你一个 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.lengthn == matrix[i].length1 <= m, n <= 10-100 <= matrix[i][j] <= 100
解题思路:模拟过程
这道题难在需要控制一下这个矩阵的行列边界,其它的并不是什么问题,照着整个流程模拟一遍就行了。
但是我们要确定的是我们按哪种方式进行遍历,比如说我们是每行每列遍历到最后一个节点的时候,包不包括最后一个节点,不同的遍历方式有不同的写法,这里给出两种,下面先来讲一下不包括边界点的遍历方式,如下图所示:
这种遍历方式会让每行每列的控制比较统一,但是会有一些问题,比如说行列数不一致以及一些循环判断问题!所以这种遍历方式我更推荐是在方阵中使用!但是这里我们还是写出代码,如下:
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if(matrix.empty())
return {}; //若数组为空,直接返回答案
vector<int> v;
int rowsize = matrix.size(), colsize = matrix[0].size(); // 矩阵的行数与列数
int startX = 0, startY = 0; // 每一圈的起始位置
int count = 1; // 计数的
int i = 0, j = 0; // 遍历每一圈的坐标
int offset = 1; // 用于控制每行每列遍历个数
// 注意这里count不能<=,这样子的话会和for循环中的判断语句冲突,会死循环
while(count < rowsize*colsize)
{
// 遍历上边(注意要判断count是否已经达到了个数)
for(j = startY; j < colsize - offset && count <= rowsize*colsize; ++j)
{
count++; // 计数++,也可也写到for循环结束执行中,但是写到循环体中更直观
v.push_back(matrix[startX][j]);
}
// 遍历右边
for(i = startX; i < rowsize - offset && count <= rowsize*colsize; ++i)
{
count++;
v.push_back(matrix[i][j]);
}
// 遍历下边
for(j; j > startY && count <= rowsize*colsize; --j)
{
count++;
v.push_back(matrix[i][j]);
}
// 遍历左边
for(i; i > startX && count <= rowsize*colsize; --i)
{
count++;
v.push_back(matrix[i][j]);
}
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startX++;
startY++;
offset++; // offset控制每一圈里每一条边遍历的长度
}
// 只有当矩阵是方阵且每行个数为奇数时才要将最中间的那个元素push进去
if(colsize % 2 == 1 && colsize == rowsize)
v.push_back(matrix[startX][colsize / 2]);
return v;
}
};注意其中有多个细节:
- 在每个 for 循环中必须加入 count <= rowsize*colsize 的判断,不然的话因为我们遍历方式的问题,会出现重复打印的情况!
- 因为我们在 while 判断中是 count < rowsize*colsize,虽然说没有将最后一个元素算入,但是我们在 for 循环中已经有 <= 的情况了,所以无需担心!
- 只有当矩阵是方阵且每行个数为奇数时才要将最后的这个最中间的那个元素push进去,这也和我们的遍历方式是有关系的!可以自行模拟过程推导!
下面给出另一种遍历方式,就是每行每列都是遍历到最后一个元素,包括最后一个元素,并且我们通过控制已经走过的行列,将其进行边界缩小,直到遇到其中一个边界越出了另一个边界,我们就可以停止循环!如下图:
这种遍历方式在这道题中会比较容易控制一点!
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
if(matrix.empty())
return {}; //若数组为空,直接返回答案
vector<int> v;
//赋值上下左右边界
int up = 0;
int down = matrix.size() - 1;
int left = 0;
int right = matrix[0].size() - 1;
while(true)
{
for(int i = left; i <= right; ++i)
v.push_back(matrix[up][i]); //向右移动直到最右
if(++up > down)
break; //重新设定上边界,若上边界大于下边界,则遍历遍历完成,下同
for(int i = up; i <= down; ++i)
v.push_back(matrix[i][right]); //向下
if(--right < left)
break; //重新设定有边界
for(int i = right; i >= left; --i)
v.push_back(matrix[down][i]); //向左
if(--down < u)
break; //重新设定下边界
for(int i = down; i >= up; --i)
v.push_back(matrix[i][left]); //向上
if(++left > right)
break; //重新设定左边界
}
return v;
}
};