59. 螺旋矩阵 II

98 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情

Day32 2023/02/07

题目链接

难度:简单

题目

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:

图片.png

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

提示:

1 <= n <= 20

思路一


本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力 ,我们只要可以用代码模拟出画全的过程即可。
具体步骤

  1. 从左到右填充上行
  2. 从上到下填充右列
  3. 从右到左填充下行
  4. 从下到上填充左列

关键点

  • 每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

算法实现


c++代码实现-过程模拟

class Solution {
  public:
    // 返回类型为一个二维数组
    vector<vector<int>> generateMatrix(int n) {
        // vector<int> res(len,
        // element);其中第一个参数为指定数组长度,第二个元素指定每个元素的初值
        vector<vector<int>> res(n, vector<int>(n, 0)); //使用vector定义一个二维数组

        int startx = 0, starty = 0; //定义每圈循环的起始位置(startx,starty)
        int loop = n / 2; //生成一个按顺时针顺序螺旋排列的n*n的的正方形矩阵,需要循环的圈数
                          //,列入n=2,则loop=1,只需要循环一圈就可以得到该矩阵
        int mid = n / 2; //当n为奇数时矩阵的中心位置
        int count = 1;   //用来给矩阵中每一个元素赋值
        int offset = 1; //需要控制不同圈中每一条边遍历的长度,即每次循环有边界都要收缩一位(n
                        //- offset)
        int i, j;

        while (loop--) {

            //下面的4个for循环就是模拟螺旋排列一圈
            //从起始位置(startx,starty)开始,模拟上行自左向右,并且遵循循环不变量(边界按照左闭右开)
            for (j = starty; j < n - offset;
                 j++) { //遍历元素即第一行第一个元素到倒数第二个(右开)
                res[startx][j] = count++;
            }

            //从位置(startx,n-offset-1)开始,模拟右列从自上向下,并且遵循循环不变量(边界按照左闭右开)
            for (i = startx; i < n - offset; i++) {
                res[i][j] = count++;
            }

            //从位置(n-offset-1,j)开始,模拟下行从自右向左,并且遵循循环不变量(边界按照左闭右开)
            for (; j > starty; j--) { //这是j = i = n - offset -1
                res[i][j] = count++;
            }

            //从位置(n-offset-1,
            //starty)开始,模拟左列从自下向上,并且遵循循环不变量(边界按照左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            //从第二圈开始,起始位置发生改变,各自加一,例如第一圈为(0,0),第二圈为(1,1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        //如果n为奇数的话,中间元素需要单独处理(单独赋值)
        if (n % 2 == 1)
            res[mid][mid] = count;

        return res;
    }
};


总结

可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开,这样便于边界条件的判定。