前端写一个函数,接收一个二维数组按从左到右,从上到下,顺时针解成一维数组,例如接收[ [1,2,3,4], [12,13,14,5], [11,16,15,6], [10,9,8,7] ] 输出 [1, 2, 3, 4,5,6,7,8,9,10,11,12,13,14,15,16]
前端解决二维数组按顺时针螺旋顺序解成一维数组的问题,是一个经典的矩阵遍历问题。我们可以使用“边界收缩”的方法来解决。
问题描述
给定一个二维数组(矩阵),按照从左到右、从上到下、顺时针的顺序遍历所有元素,并将它们放入一个一维数组中。
解决思路 (边界收缩法)
我们可以使用四个变量来表示当前螺旋遍历的边界:
top
: 当前层的上边界行索引bottom
: 当前层的下边界行索引left
: 当前层的左边界列索引right
: 当前层的右边界列索引
每次循环,我们按照顺时针方向遍历当前层的四个边,并相应地收缩边界:
-
从左到右遍历上边: 遍历
matrix[top][left]
到matrix[top][right]
。遍历完成后,top
边界向下收缩,即top++
。 -
从上到下遍历右边: 遍历
matrix[top][right]
到matrix[bottom][right]
。遍历完成后,right
边界向左收缩,即right--
。 -
从右到左遍历下边: 遍历
matrix[bottom][right]
到matrix[bottom][left]
。遍历完成后,bottom
边界向上收缩,即bottom--
。- 重要判断: 在遍历下边之前,需要检查
top <= bottom
。如果top > bottom
,说明只剩下一行或已经没有行可以遍历了,避免重复遍历或越界。
- 重要判断: 在遍历下边之前,需要检查
-
从下到上遍历左边: 遍历
matrix[bottom][left]
到matrix[top][left]
。遍历完成后,left
边界向右收缩,即left++
。- 重要判断: 在遍历左边之前,需要检查
left <= right
。如果left > right
,说明只剩下一列或已经没有列可以遍历了,避免重复遍历或越界。
- 重要判断: 在遍历左边之前,需要检查
重复以上步骤,直到 top > bottom
或 left > right
,表示所有元素都已遍历完毕。
代码实现
/**
* 将二维数组按顺时针螺旋顺序解成一维数组
* @param {number[][]} matrix - 输入的二维数组
* @returns {number[]} - 螺旋遍历后的一维数组
*/
function spiralUnwrap(matrix) {
const result = [];
// 处理空矩阵或空行的情况
if (!matrix || matrix.length === 0 || matrix[0].length === 0) {
return result;
}
let top = 0; // 上边界行索引
let bottom = matrix.length - 1; // 下边界行索引
let left = 0; // 左边界列索引
let right = matrix[0].length - 1; // 右边界列索引
// 当边界有效时循环
while (top <= bottom && left <= right) {
// 1. 从左到右遍历上边 (top row)
for (let i = left; i <= right; i++) {
result.push(matrix[top][i]);
}
top++; // 上边界向下收缩
// 2. 从上到下遍历右边 (right column)
for (let i = top; i <= bottom; i++) {
result.push(matrix[i][right]);
}
right--; // 右边界向左收缩
// 3. 从右到左遍历下边 (bottom row)
// 必须确保还有行可以遍历,防止单行矩阵重复遍历
if (top <= bottom) {
for (let i = right; i >= left; i--) {
result.push(matrix[bottom][i]);
}
bottom--; // 下边界向上收缩
}
// 4. 从下到上遍历左边 (left column)
// 必须确保还有列可以遍历,防止单列矩阵重复遍历
if (left <= right) {
for (let i = bottom; i >= top; i--) {
result.push(matrix[i][left]);
}
left++; // 左边界向右收缩
}
}
return result;
}
// 示例测试
const matrix1 = [
[1, 2, 3, 4],
[12, 13, 14, 5],
[11, 16, 15, 6],
[10, 9, 8, 7]
];
console.log("输入矩阵:", matrix1);
console.log("输出数组:", spiralUnwrap(matrix1));
// 期望输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
const matrix2 = [
[1, 2, 3],
[8, 9, 4],
[7, 6, 5]
];
console.log("输入矩阵:", matrix2);
console.log("输出数组:", spiralUnwrap(matrix2));
// 期望输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]
const matrix3 = [
[1, 2, 3, 4, 5]
];
console.log("输入矩阵:", matrix3);
console.log("输出数组:", spiralUnwrap(matrix3));
// 期望输出: [1, 2, 3, 4, 5]
const matrix4 = [
[1],
[2],
[3],
[4],
[5]
];
console.log("输入矩阵:", matrix4);
console.log("输出数组:", spiralUnwrap(matrix4));
// 期望输出: [1, 2, 3, 4, 5]
const matrix5 = [
[1]
];
console.log("输入矩阵:", matrix5);
console.log("输出数组:", spiralUnwrap(matrix5));
// 期望输出: [1]
const matrix6 = [];
console.log("输入矩阵:", matrix6);
console.log("输出数组:", spiralUnwrap(matrix6));
// 期望输出: []
const matrix7 = [
[]
];
console.log("输入矩阵:", matrix7);
console.log("输出数组:", spiralUnwrap(matrix7));
// 期望输出: []
复杂度分析
- 时间复杂度: O(M * N),其中 M 是矩阵的行数,N 是矩阵的列数。因为算法会精确地访问矩阵中的每一个元素一次。
- 空间复杂度: O(M * N),用于存储结果一维数组。如果允许修改原矩阵,并且不需要返回新的数组,那么辅助空间复杂度可以是 O(1)。