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

前端写一个函数,接收一个二维数组按从左到右,从上到下,顺时针解成一维数组,例如接收 \[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)。
相关推荐
IT_陈寒2 分钟前
Python多线程的坑,我居然现在才踩到
前端·人工智能·后端
触底反弹1 小时前
🔥 字符串算法面试三连击:反转、回文、回文变种,搞懂这三题稳了!
前端·javascript·算法
竹林8181 小时前
从 RPC 超时到批量签名:我用 @solana/web3.js 重构了一个 NFT 铸造页面,踩了这些坑
前端·javascript
工业HMI实战笔记1 小时前
工业HMI界面布局“1核2辅”黄金结构,适配90%场景
前端·ui·性能优化·自动化·交互
林希_Rachel_傻希希2 小时前
web性能优化之————图片效果
前端·javascript·面试
Darling噜啦啦2 小时前
前端存储与 this 指向完全指南:从 LocalStorage 实战到 call/apply/bind 深度解析
前端·javascript
wei1986212 小时前
.net添加web引用和添加服务引用有什么区别?
java·前端·.net
ejinxian3 小时前
Vite+ 发布新版本-整合前端工具链
前端·vite·vite+
格子软件3 小时前
2026年GEO优化系统源码级状态机与多模型调度拆解
java·前端·vue.js·人工智能·vue·geo
HUMHSX4 小时前
Vue 项目启动全流程解析:从入口文件到全局指令注册与页面渲染
前端·javascript·vue.js