小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-30 / 0 阅读
0
0

一入循环深似海 | LeetCode:59.螺旋矩阵II(转载)

一入循环深似海 | LeetCode:59.螺旋矩阵II

思路来自:代码随想录-59.螺旋矩阵II

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

示例:

输入: 3

输出:

 [
 [ 1, 2, 3 ], 
 [ 8, 9, 4 ], 
 [ 7, 6, 5 ] 
]

本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。

结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。

而求解本题依然是要坚持循环不变量(二分法也用到过)原则。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

代码执行需要遵循规则,要不就太乱了,在设计代码前先要确定规则。

此题遵循的是循环不变量原则,和左闭右开原则。这样确保了代码的规范性。

以下是题目的代码:

int main() {
    //规定初始值
   int start =1;
    int n=0;
    scanf("%d",&n);
    int a[n][n];
    int startx=0,starty=0;
    int offset = 1 ;
    //要转的圈数
    int quan  =n/2;
    int x=0,y=0;
    while (quan--) {
        //一圈一圈转,遵循循环不变量和[l,r)
        //上面部分
        //每次循环重置起始位置
       //offset 每次旋转都会少一个所以到这里停下 注意是左闭右开 的 控制每一圈收缩的程度 即:转了几圈
      for (x =startx;x<n-offset;x++ ) {
          a[starty][x]=start++;
      }
        //右边部分
      for (y=starty;y<n-offset;y++) {
          a[y][x]=start++;
      }
        //下面部分
      for (;x>startx;x--) {
          a[y][x]=start++;
      }
      for (;y>starty;y--) {
          a[y][x]=start++;
      }
        //循环结束后更新起始位置 按照对角线移动
        startx++;
        starty++;
        offset++;
    }
    //处理奇数的情况
    if (n%2==1) {
        a[n/2][n/2]=start;
    }
   //打印输出结果
    for (int i = 0; i <n; i++) {
        for (int j = 0; j <n; j++) {
           printf("%6d ",a[i][j]);
        }
        printf("\n");
    }
    return 0;
}

问题:

老师说:就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。

之前写代码就是先遍历第一行,第一行完了之后从第二行开始遍历,而没有遵循左闭右开原则,导致了一会左开右闭,一会左闭右闭。

边界太混乱。

还是建议多练习,多刷题。

54. 螺旋矩阵

我的代码:

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector <int> a;
        //获取数组维度
        int m =  matrix.size();
        int n = matrix[0].size();
        int quan = m/2+1;
        //定义每次循环的起点和终止位置
        //每次循环都是一个新的开始,不要想成和上一个连续
        //我们只需要找规律就可以了
        //圈数是 n/2 原因是 转一圈后消耗两行
        int startx=0,starty=0;
        int x=0,y=0;
        //定义 offset  我么旋转的范围是 [)  "左闭右开"
        int offset = 1;
        while(quan--){
            //模拟旋转过程 从上边旋转
            for(x=startx;x<n-offset;x++){
                a.push_back(matrix[starty][x]);
            }
            //模拟右边旋转
            for(y=starty;y<m-offset;y++){
                a.push_back(matrix[y][x]);
            }
            //模拟下面旋转
            for(;x>startx;x--){
                a.push_back(matrix[y][x]);
            }
            for(;y>starty;y--){
                 a.push_back(matrix[y][x]);
            }
            offset += 1;
            startx++;
            starty++;
        }   
        if(n%2!=0){
            a.push_back(matrix[y][x]);
        }
        return a;
    }
};

修正后的代码:

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> a;
        //获取数组维度
        int m = matrix.size();
        int n = matrix[0].size();
        int quan = min(m, n) / 2;  // 修正:圈数应该是行和列的最小值除以2
  
        //定义每次循环的起点和终止位置
        int startx = 0, starty = 0;
        int x = 0, y = 0;
        //定义 offset
        int offset = 1;
  
        while(quan--){
            //模拟旋转过程 从上边旋转
            for(x = startx; x < n - offset; x++){
                a.push_back(matrix[starty][x]);
            }
            //模拟右边旋转
            for(y = starty; y < m - offset; y++){
                a.push_back(matrix[y][x]);
            }
            //模拟下面旋转
            for(; x > startx; x--){
                a.push_back(matrix[y][x]);
            }
            //模拟左边旋转
            for(; y > starty; y--){
                a.push_back(matrix[y][x]);
            }
            offset += 1;
            startx++;
            starty++;
        }
  
        // 处理剩余的中心行或列
        if(m <= n && m % 2 == 1){  // 行数为奇数,剩余一行
            for(int i = startx; i <= n - offset; i++){
                a.push_back(matrix[starty][i]);
            }
        } else if(n < m && n % 2 == 1){  // 列数为奇数,剩余一列
            for(int i = starty; i <= m - offset; i++){
                a.push_back(matrix[i][startx]);
            }
        }
  
        return a;
    }
};

关键修改:

  1. 圈数计算quan = min(m, n) / 2 - 考虑行和列的最小值
  2. 中心处理:分别处理剩余一行或一列的情况
  3. 边界修正:在最后的循环中使用 <= 来包含边界元素

评论