题意分析

  • 给出一个n行n列的矩阵,需要我们返回这个矩阵的螺旋序列。也就是从左上角开始顺时针进行遍历,从外面往里面遍历,知道遍历了所有的数字。每个位置的数字只能被遍历一遍。

图片说明

思路分析

  • 我们可以观察得到,这个遍历的序列是从外面逐渐往里面进行扩展的。也就是先遍历完最外面的一层,然后遍历倒数第二层,倒数第三层,直到遍历完所有的数字。那么,我们就可以从这里突破,我们按照顺序先往右边进行遍历,然后往下面进行遍历,然后往左边进行遍历,最后往上面进行遍历。利用一个while循环直到遍历到的数字超过矩阵的数字的个数。
  • 还有一个要注意的就是我们需要对每个位置进行哈希,判断这个位置是否被访问过。这里我使用的是unordered_map进行处理。

解法一

  • 这种写法是直接在一个while里面先进行四个方向的遍历,然后进入下一个循环,中途使用unordered_map进行初始化。
  • 代码如下
    • 需要遍历所有的数字,并且每个位置的数字都只要遍历一遍,所以时间复杂度为O(nm)
    • 在解决问题的时候只开了少数变量,空间复杂度为O(1)
class Solution {
public:
    unordered_map<int,int> vis;  // 进行哈希存储每个位置,判断每个位置是否被访问过
    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        vector<int> ans;
        int m=matrix.size();
        if(m==0){
            return ans;
        }
        int n=matrix[0].size();


        int sum=n*m;
        int cnt=0;
        int fx=0,fy=0; // 设置起始点
        while(cnt<sum){
            // 先尽可能往左边走
            while(fy<n&&!vis[fx*sum+fy]){
                vis[fx*sum+fy]=1;
                ans.push_back(matrix[fx][fy]);
                fy++;
                cnt++;
            }
            // 回退
            fy--;
            fx++;

            // 尽可能往下边走
            while(fx<m&&!vis[fx*sum+fy]){
                vis[fx*sum+fy]=1;
                ans.push_back(matrix[fx][fy]);
                fx++;
                cnt++;
            }

            // 回退
            fx--;
            fy--;

            // 尽可能往左边走
            while(fy>=0&&!vis[fx*sum+fy]){
                vis[fx*sum+fy]=1;
                ans.push_back(matrix[fx][fy]);
                fy--;
                cnt++;
            }

            // 回退
            fy++;
            fx--;

            // 尽可能往上面走
            while(fx>=0&&!vis[fx*sum+fy]){
                vis[fx*sum+fy]=1;
                ans.push_back(matrix[fx][fy]);
                fx--;
                cnt++;
            }
            fx++;
            fy++;

            // 结束了一个环
        }

        return ans;
    }
};

解法二

  • 这种写法和上面的写法有点不一样,我们发现,最开始的外面的一圈围的是0,然后我们遍历完最外面的那层之后,我们可以在遍历的时候就将这个数字置为0,然后我们就可以利用位置上面的数字是否为0判断是否需要转换方向了。

  • 代码如下

    • 需要遍历所有的数字,并且每个位置的数字都只要遍历一遍,所以时间复杂度为O(nm)
    • 在解决问题的时候只用了少数几个变量,空间复杂度为O(1)
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int> > &matrix) {
        vector<int> ans;
        int m=matrix.size();
        int n=matrix[0].size();
        if(m==0){
            return ans;
        }
        int i=0,j=0;
        int ti=0,tj=1;
        // 从外卖呢往里面走,每循环一次,就将这一圈都更新为0
        for(int x=0;x<n*m;x++){
            ans.push_back(matrix[i][j]);
            matrix[i][j]=0; // 将这个位置置为0
            if(matrix[(i+ti)%m][(j+tj)%n]==0){
                // 将x和y的方向调换
                int tmpi=ti,tmpj=tj;
                ti=tmpj;tj=-tmpi;
            }

            // 准备执行一下圈的遍历
            i+=ti;
            j+=tj;
        }
        return ans;
    }
};