前端算法第一九五弹-螺旋矩阵 II

107 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第28天,点击查看活动详情

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

图片.png

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

模拟

模拟矩阵的生成。按照要求,初始位置设为矩阵的左上角,初始方向设为向右。若下一步的位置超出矩阵边界,或者是之前访问过的位置,则顺时针旋转,进入下一个方向。如此反复直至填入 n2n^2 个元素。

matrix\textit{matrix} 为生成的矩阵,其初始元素设为 00。由于填入的元素均为正数,我们可以判断当前位置的元素值,若不为 00,则说明已经访问过此位置。

var generateMatrix = function(n) {
    const maxNum = n * n;
    let curNum = 1;
    const matrix = new Array(n).fill(0).map(() => new Array(n).fill(0));
    let row = 0, column = 0;
    const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; // 右下左上
    let directionIndex = 0;
    while (curNum <= maxNum) {
        matrix[row][column] = curNum;
        curNum++;
        const nextRow = row + directions[directionIndex][0], nextColumn = column + directions[directionIndex][1];
        if (nextRow < 0 || nextRow >= n || nextColumn < 0 || nextColumn >= n || matrix[nextRow][nextColumn] !== 0) {
            directionIndex = (directionIndex + 1) % 4; // 顺时针旋转至下一个方向
        }
        row = row + directions[directionIndex][0];
        column = column + directions[directionIndex][1];
    }
    return matrix;
};

按层模拟

可以将矩阵看成若干层,首先填入矩阵最外层的元素,其次填入矩阵次外层的元素,直到填入矩阵最内层的元素。

定义矩阵的第 kk 层是到最近边界距离为 kk 的所有顶点。例如,下图矩阵最外层元素都是第 11 层,次外层元素都是第 22 层,最内层元素都是第 33 层。

[[1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 2, 1],
 [1, 2, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1]]

对于每层,从左上方开始以顺时针的顺序填入所有元素。假设当前层的左上角位于 (top,left)(\textit{top}, \textit{left}),右下角位于(bottom,right)(\textit{bottom}, \textit{right}),按照如下顺序填入当前层的元素。

  1. 从左到右填入上侧元素,依次为 (top,left)(\textit{top}, \textit{left})(top,right)(\textit{top}, \textit{right})
  2. 从上到下填入右侧元素,依次为 (top+1,right)(\textit{top} + 1, \textit{right})(bottom,right)(\textit{bottom}, \textit{right})
  3. 如果 left<right\textit{left} < \textit{right}top<bottom\textit{top} < \textit{bottom},则从右到左填入下侧元素,依次为 (bottom,right1)(\textit{bottom}, \textit{right} - 1)(bottom,left+1)(\textit{bottom}, \textit{left} + 1),以及从下到上填入左侧元素,依次为 (bottom,left)(\textit{bottom}, \textit{left})(top+1,left)(\textit{top} + 1, \textit{left})

填完当前层的元素之后,将 left\textit{left}top\textit{top} 分别增加 11,将 right\textit{right}bottom\textit{bottom} 分别减少 11,进入下一层继续填入元素,直到填完所有元素为止。

var generateMatrix = function(n) {
    let num = 1;
    const matrix = new Array(n).fill(0).map(() => new Array(n).fill(0));
    let left = 0, right = n - 1, top = 0, bottom = n - 1;
    while (left <= right && top <= bottom) {
        for (let column = left; column <= right; column++) {
            matrix[top][column] = num;
            num++;
        }
        for (let row = top + 1; row <= bottom; row++) {
            matrix[row][right] = num;
            num++;
        }
        if (left < right && top < bottom) {
            for (let column = right - 1; column > left; column--) {
                matrix[bottom][column] = num;
                num++;
            }
            for (let row = bottom; row > top; row--) {
                matrix[row][left] = num;
                num++;
            }
        }
        left++;
        right--;
        top++;
        bottom--;
    }
    return matrix;
};