🌱题目
🌱思路
这道题需要坚持循环不变量的原则,我们可以模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
在我们画的过程中,会发现这里的边界条件很多,很容易一进循环深似海,所以这里可以使用左闭右开的原则,如下图:
实现思路
-
坚持循环不变量的原则,边界区间左闭右开。
-
用while生成螺旋矩阵
- 首先从左到右填充上边界。
- 然后从上到下填充右边界。
- 接着从右到左填充下边界。
- 最后从下到上填充左边界。
-
循环完后更新起始位置和偏移量,为生成下一层做准备。
-
如果是n是奇数的话,就需要单独处理中间位置。
- 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
- 空间复杂度 O(1)
/**
* 生成 n x n 的螺旋矩阵
*
* 1.坚持循环不变量原则,边界区间左闭右开
* 2.while循环生成螺旋矩阵,就是二维矩阵(从左到右,从上到下,从右到左,从下到上)
* 3.如果n是奇数的话,则需要单独处理中间的值
*/
function generateMatrix(n) {
// 生成二维矩阵
let arr = new Array(n).fill(0).map(() => new Array(n).fill(0));
// 定义原点startX,startY
let startX = 0,
startY = 0;
// 计算要转多少圈和中间的位置
let loop = Math.floor(n / 2);
let mid = Math.floor(n / 2);
// 控制每一层填充的元素
let offset = 1;
// 填充的值
let count = 1;
// while循环 要确定循环多少圈
while (loop--) {
// 定义行和列的初始索引
let rowIndex = startX,
colIndex = startY;
// 从左到右
for (; colIndex < n - offset; colIndex++) {
arr[rowIndex][colIndex] = count++;
}
// 从上到下
for (; rowIndex < n - offset; rowIndex++) {
arr[rowIndex][colIndex] = count++;
}
// 从右到左
for (; colIndex > startY; colIndex--) {
arr[rowIndex][colIndex] = count++;
}
// 从下到上
for (; rowIndex > startX; rowIndex--) {
arr[rowIndex][colIndex] = count++;
}
// 判断是否有中间值,也就是n是否为奇数
if (n % 2 !== 0) {
arr[mid][mid] = count;
}
// 更新offset和初始位置
offset++;
startX++;
startY++;
}
return arr;
}
const res = generateMatrix(5);
console.log(res);
🍀类似题目
🍀总结
该题目是通过模拟螺旋填充的过程,生成一个 n x n 的螺旋矩阵。首先初始化变量和二维零矩阵,然后按照从左到右、从上到下、从右到左、从下到上的顺序填充矩阵,最后处理矩阵大小为奇数时的特殊情况,返回生成的螺旋矩阵。
这道面试题算是高频出现的题目之一,它并不要求掌握复杂的算法,而是侧重于模拟某个过程,但非常考验我们对代码的驾驭和把握能力。