NC38 螺旋矩阵
题意分析:
以顺时针螺旋方式打印出矩阵所有的元素
题解一(模拟法):
以螺旋的方式进行遍历矩阵。
使用深度优先搜索,初始时,我们向右搜索,到达边界或者下一个元素已经访问过了,就转变搜索方向。搜索方向的顺序为向右,向下,向左,向右。我们定义一个方向向量vector<pair<int,int>>direct = {{0,1},{1,0},{0,-1}, {-1,0}};,用于转变方向
代码实现如下:过程写在代码注释里
vector<pair<int, int>> direct = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; void dfs(int s, int t, vector<vector<int>> &matri, vector<vector<int>> &vis, vector<int> &ret, int &cyc) { int n = matri.size(); int m = matri[0].size(); //ret用于保存最后遍历的结果,当其大小等于m*n,遍历结束 if (ret.size() == m * n)return; //如果当前访问的位置合法且没有被访问过,就可以加入到ret中 if (s >= 0 && s < n && t >= 0 && t < m && vis[s][t] == 0) { ret.push_back(matri[s][t]); vis[s][t] = 1; } //检查下一步的位置需不需要转变方向 //下一步位置合法且没有被访问过 if (s + direct[cyc].first >= 0 && s + direct[cyc].first < n && t + direct[cyc].second >= 0 && t + direct[cyc].second < m && vis[s + direct[cyc].first][t + direct[cyc].second] == 0) { s = s + direct[cyc].first; t = t + direct[cyc].second; } else { cyc = (cyc + 1) % 4; } dfs(s, t, matri, vis, ret, cyc); } vector<int> spiralOrder(vector<vector<int>> &matrix) { if(matrix.empty()) return {}; int n = matrix.size(); int m = matrix[0].size(); vector<vector<int>> vis(n, vector<int>(m, 0)); vector<int> ret; int cyc = 0; dfs(0, 0, matrix, vis, ret, cyc); return ret; }
时间复杂度:,对矩阵所有元素遍历了一遍
空间复杂度:,申请了大小为m*n的vis矩阵用于标记矩阵是否被访问过了。
题解二(按层遍历):
这里的螺旋遍历也可以看做是顺时针访问每一层,先访问最外层,然后访问内层,依次递推。
对于每一层,从左上方以顺序遍历一层。假设当前层的左上角坐标为(left,top),右下角坐标为(right,bottom),每一层的遍历过程如下:
- 从左上到右上遍历元素,从(left,top)到(right,top),不包含(right,top)位置,
- 从右上到右下遍历元素,从(right,top)到(right,bottom),不包含(right,bottom)位置,
- 从右下到左下遍历元素,从(right,bottom)到(left,bottom),不包含(left,bottom)位置,
- 从左下到左上遍历元素,从(left,bottom)到(left,top),不包含(left,top)位置,
- 结束一层的遍历,更新(left,top)和(right,bottom),(left,top)和(right,bottom),向里走一步,,(left,top)表现为同时增1,(right,bottom)表现为减1.
- 以上过程适合某一层为方形,当某一层变为一行,或者一列,后者只剩一个元素了,我们单独拎出来遍历即可。
结束遍历:当(left,top)跑到(right,bottom)的右下,或者在同一行或者同一列的时候结束遍历,处理剩下的。
代码实现如下:
vector<int> spiralOrder(vector<vector<int>> &matrix) { if (matrix.empty()) return {}; int m = matrix.size(), n = matrix[0].size(); vector<int> ret; int left = 0, top = 0, right = n - 1, bottom = m - 1; while (left <right && top <bottom) { //按照四个方向,对一层进行遍历 //上方,从左到右 for (int i = left; i < right; i++) { ret.push_back(matrix[top][i]); } //右方,从上到下 for (int i = top; i < bottom; i++) { ret.push_back(matrix[i][right]); } //下方,从右到左 for (int i = right; i > left; i--) { ret.push_back(matrix[bottom][i]); } //左方,从下到上 for (int i = bottom; i > top; i--) { ret.push_back(matrix[i][left]); } left++; right--; top++; bottom--; } //当剩下的元素仅有一个 if(left==right&top==bottom){ ret.push_back(matrix[left][top]); } //当剩下的元素不能围成一个矩形,是一个条带的时候 else if(top==bottom){ for (int i = left; i <=right; i++) { ret.push_back(matrix[top][i]); } } else if(left==right){ for (int i = top; i <= bottom; i++) { ret.push_back(matrix[i][right]); } } return ret; }
时间复杂度:,我们自外向里对所有有元素进行了一次遍历,没有重复遍历任何元素,访问的元素个数为m*n。
空间复杂度:,没有申请额外的数组。