トピック:
正の整数を指定すると 、 すべての 要素n
を含む正方行列 (n✖️n 正方行列) が生成され、要素は時計回りの 順序 で螺旋状に配置されます 。1
n2
n x n
matrix
例:
入力 n=3、出力:
上の図に示すように、埋める必要があるエッジは合計 4 つあります。左閉じ右開きルールに従って、時計回りに埋めていく必要があります。最後の位置は次のエッジに引き継がれます。は:
上 ---> 左から右へ
右列 ---> 上から下へ
下--->右から左へ
左列 ---> 下から上へ
各ラウンドのトラバースの後、次のラウンドのトラバースの開始位置は +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
}
二分法と比較して、この問題はループの不変量の制御をテストするものであり、ループ内の区間の定義を主張することによってのみ、ループの詳細をよりよく理解することができます。