『JavaScript』二维数组螺旋扁平化
1. 问题引入
在准备蓝桥杯 Web 赛项的时候,遇到过一个问题:
公主被关在地图中央,骑⼠最开始在⼆维地图 [0, 0] 的位置。补全 mazePath 函数,将起点到终点顺时针经过的每个元素(即 class 包含 box ) data-index 属性值依次保存在数组中并返回。
来源:《第十四届蓝桥杯国赛(Web 应用开发) 大学组 - “恶龙与公主”》
下图是游戏的迷宫界面,意思是我们需要把一个 5 * 5 的二维数组按照顺时针的顺序转化为一维数组。
现在,我们要开发一个通用方法,将 row * column 的二维数组(矩阵)按规则转化为一维数组。暂且将这个方法称为 二维数组螺旋扁平化
,下面将介绍二维数组的 顺时针螺旋扁平化
和 逆时针螺旋扁平化
。
2. 步骤分析
我们对这个 5*5 的矩阵进行顺时针分析。
首先要把第一排的数组全部添加到结果数组中,可以使用 shift()
方法取出第一行所有元素,添加到临时数组中。
现在假设第一行被删除了,剩下下面的 4*5 数组。再把每一行的最后一个元素 pop()
出来,添加到临时数组中。
紧接着还剩左下角 4*4 的数组,可以通过 pop()
取出最后一行所有元素;但是现在整个数组是顺序的,需要通过 reverse()
把最后一行逆序,添加到临时数组中。
最后就是倒序遍历数组,依次 unshift()
每一行的第一个元素,添加到临时数组中。
还剩下中间的 3*3 数组,再顺序执行前面的步骤,直到数组中没有元素。
3. 生成测试用例
这是题目中给定的测试用例:
const array1 = [
['start', 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 'end', 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]
];
当然我们也可以自己生成测试用例:
/**
* 生成一个指定行数和列数的二维数组,数组元素从1开始顺序递增
*
* @param {number} rows 行数
* @param {number} columns 列数
* @returns {number[][]} 二维数组
*/
function generateNumberMatrix(rows, columns) {
const result = [];
// 扁平化数组长度
const length = rows * columns;
// 生成矩阵
for (let i = 0; i < length; i++) {
// 计算行下标
const rowIndex = Math.floor(i / columns);
// 创建行
if (!result?.[rowIndex]) result.push([]);
// 在行中添加元素
result[rowIndex].push(i + 1)
}
return result;
}
4. 顺时针螺旋扁平化
/**
* 将二维数组顺时针展开为一维数组
*
* @param {Array<Array>} arr 二维数组
* @returns {Array} 一维数组
*/
function clockwiseSpiralFlatten(arr) {
const result = [];
while (arr.length) {
// 从左到右
result.push(...arr.shift());
// 从上到下
for (const row of arr) {
if (row.length) result.push(row.pop());
}
// 从右到左
if (arr.length) result.push(...arr.pop().reverse());
// 从下到上
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i].length) result.push(arr[i].shift());
}
}
return result;
}
测试:
// 题目用例
console.log(clockwiseSpiralFlatten(array1));
// 6*3 矩阵
const array2 = generateNumberMatrix(6, 3);
console.log(clockwiseSpiralFlatten(array2));
// 测试结果
// ['start', 1, 2, 3, 4, 9, 14, 19, 24, 23, 22, 21, 20, 15, 10, 5, 6, 7, 8, 13, 18, 17, 16, 11, 'end']
// [1, 2, 3, 6, 9, 12, 15, 18, 17, 16, 13, 10, 7, 4, 5, 8, 11, 14]
在线运行:
5. 逆时针螺旋扁平化
/**
* 将二维数组逆时针展开为一维数组
*
* @param {Array<Array>} arr 二维数组
* @returns {Array} 一维数组
*/
function counterClockwiseSpiralFlatten(arr) {
const result = [];
while (arr.length) {
// 从上到下
for (const row of arr) {
if (row.length) result.push(row.shift());
}
// 从左到右
result.push(...arr.pop());
// 从下到上
for (let i = arr.length - 1; i >= 0; i--) {
if (arr[i].length) result.push(arr[i].pop());
}
// 从右到左
if (arr.length) result.push(...arr.shift().reverse());
}
return result;
}
测试:
// 题目用例
console.log(counterClockwiseSpiralFlatten(array1));
// 3*4 矩阵
const array2 = generateNumberMatrix(3, 4);
console.log(counterClockwiseSpiralFlatten(array2));
// 测试结果
// ['start', 5, 10, 15, 20, 21, 22, 23, 24, 19, 14, 9, 4, 3, 2, 1, 6, 11, 16, 17, 18, 13, 8, 7, 'end']
// [1, 5, 9, 10, 11, 12, 8, 4, 3, 2, 6, 7]
在线运行: