给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入:3
输出:[[1,2,3],[8,9,4],[7,6,5]]
顺时针螺旋排列的矩阵是什么意思呢,以3*3的矩阵为例
3*3=9,将1到9的数按顺序从矩阵最外圈开始排列,一圈一圈(类似贪吃蛇的感觉)向内排列,直到到达矩阵最中间。
具体的思路如《代码随想录》所示。我这里依旧对代码进行详细解释说明。
完整代码如下:
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
nums = [[0] * n for _ in range(n)]
startx, starty = 0, 0 # 起始点
loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点
count = 1 # 计数
for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始
for i in range(starty, n - offset) : # 从左至右,左闭右开
nums[startx][i] = count
count += 1
for i in range(startx, n - offset) : # 从上至下
nums[i][n - offset] = count
count += 1
for i in range(n - offset, starty, -1) : # 从右至左
nums[n - offset][i] = count
count += 1
for i in range(n - offset, startx, -1) : # 从下至上
nums[i][starty] = count
count += 1
startx += 1 # 更新起始点
starty += 1
if n % 2 != 0 : # n为奇数时,填充中心点
nums[mid][mid] = count
return nums
首先,设置一个所有数为0的n*n阶的矩阵
nums = [[0] * n for _ in range(n)]
其中[0]*n代表矩阵第一行,例如[0]*3,则代表生成一个数组为[0,0,0]。在生成一个数组后加入n层的for循环代表生成n行与第一个数组一样的数组,最终形成n*n阶的矩阵。
startx, starty = 0, 0 # 起始点
loop, mid = n // 2, n // 2 # 迭代次数、n为奇数时,矩阵的中心点
count = 1 # 计数
上述代码中startx可以理解为第几行,starty可以理解为第几列,是为方便后面将具体数字填充至第几行第几列,这里面初始为0也是因为下标是从0开始的。
loop代表迭代次数(n除以2后的整数部分),可以理解为能在一个n*n阶的矩阵中完成几次完整的绕四边一圈的次数。同时当n为奇数时,矩阵存在最后一圈完不成的情况即矩阵存在中心点,因此用mid=n//2来表示矩阵中心点,即nums[mid][mid]为矩阵中心点。
最后一行的count=1则代表的是第一个填充的元素1。
for offset in range(1, loop + 1) : # 每循环一层偏移量加1,偏移量从1开始
for i in range(starty, n - offset) : # 从左至右,左闭右开
nums[startx][i] = count
count += 1
从最外圈开始第一次迭代。为保证代码统一,将每条边的元素填充方法设计为只填充至倒数第二格,如下图所示。
因此,在代码中可以体现为每条边的元素填充都是一个左闭右开区间,如n=3时,第一次迭代时 for i in range(starty, n - offset)中starty = 0 ,n-offset=2,即区间为[0,2),第一次的nums[startx][i] = count即代表nums[0][0] = 1即空矩阵第一行第一列填充为1,count+1代表下次开始填充元素为2,依次填充,这样第一条边除最后一个值便都填充完毕了。接着,依次是右边、下边以及左边。
startx += 1 # 更新起始点
starty += 1
最外圈的边都填充完毕后,开始对里面一圈的边进行填充,则更新起点startx和starty就可以了,迭代次数有几次则完成几圈。
if n % 2 != 0 : # n为奇数时,填充中心点
nums[mid][mid] = count
return nums
最后,当m为奇数时,填充矩阵的中心点nums[mid][mid],将其填充为最终叠加后的count,其实也等于n*n的值,最后return整个填充完毕的螺旋矩阵nums。