您的位置:首页 > 其它

每天一道LeetCode-----将m × n矩阵按照顺时针螺旋顺序转化成一维数组

2017-11-17 14:17 471 查看

Spiral Matrix

原题链接Spiral Matrix



给定一个m × n矩阵,按照顺时针螺旋顺序将矩阵转化成一维数组。

螺旋的方向是先从左向右,再从上到下,然后从右到左,最后从下到上。

所以方向可以用
{0, 1},{1, 0},{0, -1},{-1, 0}
四个方向向量表示。每个方向向量都由行和列构成,1表示向右或向下移动,-1表示向左或向上移动,0表示不移动。比方说{0, 1}表示行不移动,列从左向右移动。

可以发现,方向是固定先向右,再向下,然后向左,最后向上,正好对应上面四个方向向量,如果将这四个方向向量存在vector中,那么可以找一个变量记录方向,即0, 1, 2, 3分别对应上述的方向向量(下标)。每在一个方向上移动完成,就要更换方向,也就是将这个变量加一,不过要记得 % 4

再举个5 × 3矩阵的例子(m = 5,n = 3)

*   *   *
*   *   *
*   *   *
*   *   *
*   *   *


可以看到,移动的过程是

第一圈

向右移动3步

向下移动4步

向左移动2步

向上移动3步

第二圈

向右移动1步

向下移动2步

结束

将水平方向移动步数和垂直方向移动步数分别提取出来

水平方向

向右移动3步

向左移动2步

向右移动1步

垂直方向

向下移动4步

向上移动3步

向下移动2步

可以看到,在水平方向上,移动的步数每次都是减一,垂直方向上也是如此。

而初始时,水平方向可以移动3步,也就是列数n。垂直方向上可以移动4步,是行数m - 1。

那么就可以使用两个变量记录水平方向和垂直方向上下次可以移动多少步。

利用以上两个条件

用方向向量表示当前是应该向哪个方向移动

记录当前方向可以移动多少步

就可以解决问题

代码如下

class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> res;
int nr = matrix.size();
if(nr == 0) { return res; }
int nc = matrix[0].size();
if(nc == 0) { return res; }

/* 方向向量 */
vector<vector<int>> dirs{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
/* 行/列分别可以移动多少步,初始时行可以移动列数步,列可以移动行数-1步 */
vector<int> steps{nc, nr - 1};
/* [ir, ic]记录当前的位置,初始为[0, -1] */
int ir = 0;
int ic = -1;
/* idir记录当前的方向,可以是0,1,2,3 */
int idir = 0;
/* 如果当前方向上仍然可以移动,就继续移动 */
while(steps[idir % 2])
{
/* idir % 2表示是水平还是垂直方向,steps[idir % 2]表示当前方向还可以移动多少步 */
for(int i = 0; i < steps[idir % 2]; ++i)
{
/* dirs[idir]表示当前方向 */
ir += dirs[idir][0];
ic += dirs[idir][1];
res.emplace_back(matrix[ir][ic]);
}
/* 每移动一个方向,对应剩余步数减一 */
--steps[idir % 2];
/* 改变方向 */
idir = (idir + 1) % 4;
}
return res;
}
};


Spiral Matrix II

原题链接Spiral Matrix II



其实就是上面题的逆序,给出一个一维数组,按顺时针螺旋顺序生成一个矩阵,方法一样

class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n));
if(n == 0)
return res;

vector<vector<int>> dirs{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
vector<int> steps{n, n - 1};
int ir = 0;
int ic = -1;
int dir = 0;
int num = 1;
while(steps[dir % 2])
{
for(int i = 0; i < steps[dir % 2]; ++i)
{
ir += dirs[dir][0];
ic += dirs[dir][1];
/* 这里改为赋值 */
res[ir][ic] = num++;
}
--steps[dir % 2];
dir = (dir + 1) % 4;
}
return res;
}
};


上面两道题主要是将方向转为方向向量进行解决,因为固定只有四种方向,所以可以用{0, 1}, {1, 0}, {0, -1}, {-1, 0}四个方向向量表示向右,向下,向左和向上四个方向。同时需要用一个变量记录当前是在哪个方向上,0,1,2,3分别代表四个方向,即作为方向向量的下标。

另外每个方向上的移动是递减的,每移动一次,这个方向上下次移动的步数会减一,直到为0为止。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode
相关文章推荐