每天一道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-----给定字符串s和字符数组words,在s中找到words出现的位置,words内部字符串顺序无要求
- 每天一道LeetCode-----将数值数组按一定顺序拼接,使得拼接的结果最大
- 每天一道LeetCode-----顺时针旋转n×n矩阵90度
- java 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,
- 每天一道LeetCode-----在给定数组中找到一个子数组,使得这个子数组的元素乘积最大
- C++输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,
- 每天一道LeetCode-----有序数组循环右移n位后,寻找最小值,数组中可能包含重复元素
- 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8
- 1,2,3…n*n 的数字按照顺时针螺旋的形式打印成矩阵(递归)
- 每天一道算法题——顺时针打印矩阵
- 每天一道LeetCode-----将数组/链表后k个元素移动到前面
- 每天一道LeetCode-----重排链表,节点顺序是从头取一个,从尾取一个,从头取一个,从尾取一个.....
- [python] 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字[顺时针打印矩阵]
- 按照顺时针的顺序从外向里打印整形数组
- 每天一道LeetCode-----找到一个字符串在另一个字符串出现的位置,字符串内部顺序无要求
- 输入一个矩阵,按照从外向里顺时针的顺序依次打印出每一个数字
- java-51-输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
- [数组]顺时针打印螺旋矩阵
- 对一维顺序数组螺旋输出到二维数组
- 输入一个矩阵,按照从外到里以顺时针的顺序依次打印每一个数字