二维数组按顺时针螺旋顺序

前端写一个函数,接收一个二维数组按从左到右,从上到下,顺时针解成一维数组,例如接收[ [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: 当前层的右边界列索引

每次循环,我们按照顺时针方向遍历当前层的四个边,并相应地收缩边界:

  1. 从左到右遍历上边: 遍历 matrix[top][left]matrix[top][right]。遍历完成后,top 边界向下收缩,即 top++

  2. 从上到下遍历右边: 遍历 matrix[top][right]matrix[bottom][right]。遍历完成后,right 边界向左收缩,即 right--

  3. 从右到左遍历下边: 遍历 matrix[bottom][right]matrix[bottom][left]。遍历完成后,bottom 边界向上收缩,即 bottom--

    • 重要判断: 在遍历下边之前,需要检查 top <= bottom。如果 top > bottom,说明只剩下一行或已经没有行可以遍历了,避免重复遍历或越界。
  4. 从下到上遍历左边: 遍历 matrix[bottom][left]matrix[top][left]。遍历完成后,left 边界向右收缩,即 left++

    • 重要判断: 在遍历左边之前,需要检查 left <= right。如果 left > right,说明只剩下一列或已经没有列可以遍历了,避免重复遍历或越界。

重复以上步骤,直到 top > bottomleft > right,表示所有元素都已遍历完毕。

代码实现

js 复制代码
/**
 * 将二维数组按顺时针螺旋顺序解成一维数组
 * @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)。
相关推荐
gnip2 小时前
链式调用和延迟执行
前端·javascript
SoaringHeart2 小时前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.2 小时前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频
Dragon Wu2 小时前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架
Jinuss2 小时前
Vue3源码reactivity响应式篇之watch实现
前端·vue3
YU大宗师2 小时前
React面试题
前端·javascript·react.js
木兮xg2 小时前
react基础篇
前端·react.js·前端框架
ssshooter3 小时前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
IT利刃出鞘3 小时前
HTML--最简的二级菜单页面
前端·html
yume_sibai3 小时前
HTML HTML基础(4)
前端·html