🎯 本文详细解析了LeetCode螺旋矩阵II问题的解法。通过一圈一圈填充矩阵的方式,将复杂问题分解为顶行、右列、底行、左列四步操作,每圈填充数量随圈数递减。文中清晰阐述了遍历规律与代码实现逻辑,包括如何确定起点、终点及循环次数,并特别处理了奇数阶矩阵中心元素的填充问题。附带完整Java代码示例,帮助读者理解并掌握这一经典算法题的解决思路。
📖题目📖
题目链接:leetcode.cn/problems/sp...

很多读者看到这道题没理清思路,然后就开始写代码,试来试去提交都有问题。
做这道题,首先需要找一个统一的规律,然后实现起来比较绕,对代码能力也有要求
💱找规律💱
如何填充

- 一圈一圈来填充(第一圈是浅绿色,第二圈是浅蓝色)
- 填充一个圈的时候,需要分为四步来操作,即分别填充圈的顶行、右列、底行、左列。假如圈是 n 行 n 列,则顶行、右列、底行、左列 分别填充 n-1 个数。
- 如第 0 圈,是 5行5列 ,那每一步就填充 4 个数字。
- 第一步填充 1、2、3、4
- 第二步填充 5、6、7、8
- 第三步填充 9、10、11、12
- 第四步填充 13、14、15、16
从当前圈到下一圈的规律
- 填充完一圈之后,下一步就是往里面走一圈。
- 如果当前圈是 n 行 n 列,那往里走一圈就是 n-2 行 n-2 列。姐每往里走一圈,行数、列数都要减 2 。
- 第 0 圈:5 行 5 列;
- 第 1 圈:3 行 3 列;
- 第 2 圈:1 行 1 列
💱如何遍历💱
遍历哪行哪列数据
以顶行填充为例,第 0 圈填充的第 0 行;第 1 圈填充的第 1 行。即第几圈遍历第几行,因此使用一个变量circleNum
来表示当前遍历的圈数。
遍历怎么写
如何知道一个循环要怎么写,需要分别确定起点 start 和终点 end。end-start
就是循环次数。那我们只要知道 start
和循环次数
即可
java
for (int i = start; i < end; i++) {
}
循环次数如何确定
每一步遍历多少个数?
- 在 5 行 5 列的矩阵填充中,第 0 圈每一步遍历 4 个数,第 1 圈遍历 2 个数,第 2 圈遍历 0 个数(第 2 圈只剩下一个数,不需要遍历处理了,最后额外处理一下就行,不理解直接看代码实现小节)。
- 即一开始维护一个变量
number=n-1
,每走完一圈,number
减少 2 即可
遍历起点是啥
以顶行为例,第 0 圈从 0 开始遍历,第 1 圈从 1 开始遍历。因此遍历起点是circleNum
java
for (int j = circleNum; j < circleNum + number; j++) {
result[circleNum][j] = ++curNum;
}
右列、底行、左列 规律也依此类推
🧑💻代码实现🧑💻
代码中 number>0
才继续循环,在 5 行 5 列矩阵中,最后的 25 是没有填充的。那怎么填充这个数字呢?
其实直接设置中间的格子就行
java
if (curNum < n * n) {
result[n / 2][n / 2] = n * n;
}
当然,只有 n 为单数的时候,才需要额外设置。n 为复数的时候,没有漏单的元素,如下图所示

java
public static int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
// 遍历次数
int number = n - 1;
// 走过的圈数
int circleNum = 0;
// 当前要填充的数字
int curNum = 0;
while (number > 0) {
/// 顶行填充
// 第一圈填充的第一行;第二圈填充的第二行
// 因此,处理第几圈,就是遍历第几行
for (int j = circleNum; j < circleNum + number; j++) {
result[circleNum][j] = ++curNum;
}
/// 右列填充
// 第一圈填充的最后一列(n-1);第二圈填充的倒数第二列(n-2)
// 因此,第几圈,就是倒数第几列
// 总结为处理 n - circleNum - 1
for (int i = circleNum; i < circleNum + number; i++) {
result[i][n - circleNum - 1] = ++curNum;
}
// 底行填充
for (int j = circleNum; j < circleNum + number; j++) {
result[n - circleNum - 1][n - j - 1] = ++curNum;
}
// 左列填充
for (int i = circleNum; i < circleNum + number; i++) {
result[n - i - 1][circleNum] = ++curNum;
}
// 没转一圈,要遍历的次数就少俩
number -= 2;
// 圈数 +1
circleNum++;
}
// --if-- 如果剩下最后一个格子没有填,填充最后一个格子
if (curNum < n * n) {
result[n / 2][n / 2] = n * n;
}
return result;
}
