题目:
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素(n✖️n的正方形矩阵),且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例:
输入n=3, 输出:
根据上图所示, 一共有四条边需要填充,要按照顺时针进行,遵循左闭右开规则,最后一个位置交给下一条边处理,分别是:
上行--->从左到右
右行--->从上到下
下行--->从右到左
左行--->从下到上
每遍历完一圈,下一圈遍历的起始位置就要+1,结束的边界位置也要-1
如果n为奇数 我们还要处理中间值 n为偶数时遍历完就填充好了 奇数会漏掉中间的位置 需要手动填充
捋清楚整个过程后,代码实现:
/**
* @description 生成n*n螺旋矩阵
* @param {number} n 要生成矩阵的边长
* @return {number[][]}
* */
function generateMatrix(n) {
let startX = (startY = 0) // 每圈遍历的起始位置
let loop = n >> 1 // 遍历的圈数 只需要遍历Math.floor(n/2)圈
let mid = n >> 1 // 中间位置索引 n为奇数时需要单独填充中间值 位置(x,y)为(Math.floor(n/2), Math.floor(n/2))
let count = 1 // 填充的值 每填充一次++
let offset = 1 // 每遍历一圈边界缩小一位
const result = new Array(n).fill(0).map((e) => new Array(n).fill(0)) // 初始化一个n*n的二维数组做为矩阵
// 循环的条件就是圈数 遍历一圈就-- 为0时false结束遍历
while (loop--) {
// 每圈开始初始化行和列变量
let col = startX
let row = startY
// 左闭右开原则 每条边的最后一个位置交给下一条边的第一个填充
// 从上行开始 从左到右遍历<n-offset次
for (; col < n - offset; col++) {
result[row][col] = count++
}
// 右行从上到下遍历<n-offset次 此时col到了右边最后一个且在这个循环恒定不变
for (; row < n - offset; row++) {
result[row][col] = count++ // 填充第col列每一行右行的值
}
// 下行从右到左 所以col要--来控制填充顺序 直到col===startX停止 当遍历到startX则到了这一圈这条边要填充的最后一个
for (; col > startX; col--) {
result[row][col] = count++ // 此时的row为最后一行且在这个循环恒定不变
}
// 左行从下到上 row要--来控制从下往上填充 直到row===startY停止 当遍历到startY则到了这一圈这条边要填充的最后一个
for (; row > startY; row--) {
result[row][col] = count++
}
// 填充完一圈将下一圈填充的起始位置+1 边界值也要+1
startX++
startY++
offset++
}
// 圈都填充完后 判断矩阵是否有中间位置 边长为偶数的矩阵没有中间值 如果n是奇数则有中间值 手动填充
if ((n & 1) === 1) {
result[mid][mid] = count
}
return result
}
这道题相比二分法更加考验了对循环不变量的控制,只有在循环中坚持对区间的定义,才能更好的把握循环里的各个细节