拿下螺旋矩阵!LeetCode 59. 螺旋矩阵II,一招学会循环不变量

1 阅读3分钟

拿下螺旋矩阵!LeetCode 59. 螺旋矩阵II,一招学会循环不变量

题目本身不涉及高深算法,却极其考验对代码的掌控能力。本文将带你用“循环不变量”原则,轻松攻克这道题。

题目描述

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

示例:

text

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

解题思路

这道题就是典型的模拟过程题目。我们需要按照顺时针方向,一圈一圈地给矩阵填充数字:

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

然而,边界条件非常多。很多同学写的时候一会儿左闭右开,一会儿左闭右闭,最后代码越写越乱,一进循环深似海。

核心方法论:循环不变量

要写好这道题,必须坚持循环不变量原则。通俗说,就是在每一圈的每一条边上,都采用相同的区间规则

本文采用左闭右开原则。即每条边只处理起点,不处理终点,拐角处的元素交给下一条边来处理。

一圈的拆解(左闭右开)

假设我们画边长为4的正方形,一圈的遍历如下:

  • 上行:从左到右,遍历 [start, n-offset)
  • 右列:从上到下,遍历 [start, n-offset)
  • 下行:从右到左,遍历 (start, n-offset] 逆序,但左闭右开写法其实也是 j > startY 作为边界
  • 左列:从下到上,遍历 i > startX

这样做的好处是:每条边的处理规则完全一致,不会出现边界冲突。

代码详解(JavaScript版)

javascript

var generateMatrix = function(n) {
    // 初始化二维数组
    let res = new Array(n).fill().map(() => new Array(n).fill(0));
    
    let startX = 0, startY = 0;    // 每圈起始坐标
    let loop = Math.floor(n / 2);   // 需要转的圈数
    let mid = Math.floor(n / 2);    // 中心点坐标(n为奇数时)
    let count = 1;                  // 填充数字
    let offset = 1;                // 控制边长度
    
    let i, j;
    
    while (loop--) {
        i = startX;
        j = startY;
        
        // 1. 上行:从左到右
        for (j = startY; j < n - offset; j++) {
            res[i][j] = count++;
        }
        
        // 2. 右列:从上到下
        for (i = startX; i < n - offset; i++) {
            res[i][j] = count++;
        }
        
        // 3. 下行:从右到左
        for (; j > startY; j--) {
            res[i][j] = count++;
        }
        
        // 4. 左列:从下到上
        for (; i > startX; i--) {
            res[i][j] = count++;
        }
        
        // 下一圈起始位置向内缩一格
        startX++;
        startY++;
        // 边长缩减
        offset += 1;
    }
    
    // n为奇数时,中心点单独赋值
    if (n % 2 === 1) {
        res[mid][mid] = count;
    }
    
    return res;
};

测试用例

javascript

console.log(generateMatrix(3));
// 输出: [[1,2,3],[8,9,4],[7,6,5]]

console.log(generateMatrix(4));
// 输出: 4x4 螺旋矩阵

复杂度分析

  • 时间复杂度:O(n²),需要遍历矩阵的每一个元素。
  • 空间复杂度:O(1),除了返回结果数组外,只使用了常数个额外变量。

总结

通过这道题,我们要记住:

  1. 模拟类题目一定要先规划好边界规则。
  2. 循环不变量 是写出正确边界控制的关键。
  3. 坚持左闭右开能让代码逻辑清晰,避免混乱。

推荐搭配视频学习:《代码随想录》算法视频公开课(拿下螺旋矩阵)

掌握了这个方法,无论 n 多大,我们都能有条不紊地画出螺旋矩阵。快去试试吧!