编辑代码

//JSRUN引擎2.0,支持多达30种语言在线运行,全仿真在线交互输入输出。 
console.log("Hello world!            -  js.jsrun.net ");
function spiral2DArray(n, m, step = 1) {
        // n是二维数组的行,m是二维数组的列,n,m是从1开始  i,j是从0开始
        // 螺旋圈数
        let layer = Math.ceil(Math.min(n, m) / 2);
        // 每一圈包含的元素数
        let layerSum = new Array(layer).fill(0).map((item, k) => {
            // 当前圈的面积减去下一层圈的面积
            let now = (n - 2 * k) * (m - 2 * k);
            let next = (k + 1) >= layer ? 0 : (n - 2 * (k + 1)) * (m - 2 * (k + 1))
            return now - next
        })
        // 边界值限制
        function isOver(i, j) {
            if (i >= n || j >= m) {
                console.log('超出范围')
            }
            return i >= n || j >= m;
        }
        // 只单独从行和单独从列 计算所处的圈层;
        function getSpiral(i, j) {
            let x, y;
            x = i < layer ? (i + 1) : (n - i)
            y = j < layer ? (j + 1) : (m - j)
            return { x, y };
        }
        // 此二维下标处在第几圈
        function getLayer(i, j) {
            if (isOver(i, j)) return;
            // 计算 (i, j) 在第几圈
            let { x, y } = getSpiral(i, j);
            return Math.min(x, y);
        }
        // 此二维下标在当前圈相对顺序位置 相对位置从1开始计算
        function getPosition(i, j) {
            if (isOver(i, j)) return;
            let layerTh = getLayer(i, j);
            // 当前圈的宽度和高度 所占据的元素个数
            let widthLength = m - 2 * (layerTh - 1);
            // 首尾的元素被宽算入了 所以高度的元素数量就不再算入
            let heightLength = n - 2 * (layerTh - 1) - 2;
            let { x, y } = getSpiral(i, j);
            // 算法本天成 妙手偶得之, 
            // 不要问我它啥意思,我只是随便写写大概公式然后调整到符合结果.如果你知道啥意思请告诉我.
            if (x <= y && i + 1 == x) {
                // 元素位于当前圈的上边
                return j + 1 - x + 1;
            }
            else if (x <= y) {
                // x <= y 上下边 i + 1 == x上边挑剩的就是下边
                return widthLength + heightLength -2*(x + 1) + (widthLength-j-1 );
            }
            else if (x > y && j + 1 == y) {
                // 元素位于当前圈的左边
                return widthLength + widthLength + heightLength + (heightLength +  y - i);
            }
            else if (x > y) {
                // // x > y左右边 j + 1 == y左边挑剩的就是右边
                return widthLength + i - y + 1;
            }
        }
        // 根据圈层数和所在圈层数的相对顺序位置 得出此二维标的具体数字
        function getNum(i, j) {
            if (isOver(i, j)) return;
            let layerTh = getLayer(i, j);
            let positionNum = getPosition(i, j);
            // 当前圈的前几圈的元素和 加上当前圈的当前元素的相对顺序位置
            let res = (layerSum.slice(0, layerTh - 1).reduce((r, c) => r + c, 0) || 0) + positionNum;
            return res * step;
        }
        function getArray() {
            let arr = new Array(n).fill(0).map((item) => item = new Array(m).fill(0));
            arr.forEach((items, i) => {
                arr[i] = items.map((item, j) => {
                    return getNum(i, j)
                })
            })
            return arr
        }
        return {
            layer,// 螺旋圈数
            layerSum, // 每一圈包含的元素数
            getLayer, // 获取此二维下标处在第几圈
            getPosition, // 获取此二维下标在当前圈相对顺序位置
            getNum, // 获取此二维下标的具体数字
            getArray, // 获取本二维螺旋数组
        };
    }
    const row = 5, col = 5; step = 1;
    // 正常用法 直接取结果
    let spiralArrayInfo = spiral2DArray(row, col, step);
    console.log('二维螺旋数组:', spiralArrayInfo.getArray())
    console.log('总圈数:', spiralArrayInfo.layer)
    console.log('每一圈的元素个数:', spiralArrayInfo.layerSum)
    console.log('2,3坐标处所在的圈数:', spiralArrayInfo.getLayer(2, 3))
    console.log('2,3坐标处在它自己所在圈数的相对顺序位置:', spiralArrayInfo.getPosition(2, 3))
    console.log('2,3坐标处的值:', spiralArrayInfo.getNum(2, 3))