59. 螺旋矩阵 II

发布时间 2023-12-14 13:40:38作者: 庄子游世

题目:

59. 螺旋矩阵 II

要求:

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

答案:

两种解法:

一种用计算机模拟顺时针旋转的效果,这种方法看起来容易,做起来并没有那么容易,我开始就用这个思路做的,结果发现写不出来,看了下题解,才写出来,我写不出来的点就是在旋转的地方没有做到,我想着每一个点都是一种情况,没有总结出通用的旋转情况,并且没有使用下一个位置来做旋转,而是判断当前位置来做旋转,这是其一;其二是每一个定点旋转其实规律是相同的,官方题解给出了一个二维数组就非常巧妙,单独定义了一个旋转点来作为二维数组的横坐标,横坐标就分别代表了向右、向下、向左、向上,思路简单,代码不好写呀。

第二种是层级思维,每次遍历一层,也就是最外面一层,这个时候不需要考虑边界,只要定义四个定点就行,在每遍历一层,修改四个定点就可以,四个定点分别是每一层开始的横坐标(left)、纵坐标(top)、结束的横坐标(right)、结束的纵坐标(bottom),其实开始的横纵坐标一定是相等的,用一个变量也可以,方便理解还是分开表示,这样每遍历一层,坐标变化是 left + 1top + 1right - 1bottom - 1 ,循环结束的条件就是 left ≤ righttop ≤ bottom ,为什么要相等呢?因为奇数的时候,最中间的位置横纵索引是相同的。至于在赋值的时候什么时候给边界赋值,就是 for 循环上添加等号就可以,不可重复给同一个位置赋值,这点很重要。

/**
 * 遇到边界或者访问过的元素,就顺时针转动,关键是代码怎么写,如何确定边界很关键。
 * 这里声明了一个二维数组确定下一个位置,声明一个变量用来确定方向,为什么要确定下一个位置,因为要根据下一个位置来确定是不是要转向,
 * 也就是下一个位置如果处于边界或者已经访问过,则顺时针转向
 *
 * @param n 二维数组的长度
 * @return 二维数组
 */
public static int[][] generateMatrix(int n) {
    int[][] result = new int[n][n];
    // 四个方向,分别代表了右、下、左、上
    int[][] direct = new int[][] {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    // 代表了方向,因为是四个方向,所以和 4 取余
    int steering = 0;
    // 初始化行、列
    int num = 1, row = 0, col = 0;
    while (num <= n * n) {
        result[row][col] = num;
        num++;
        // 确定下一个位置,并不是真实的下一个位置,而是根据当下的情况确定下一个位置,用于判断是否是边界或者是否已经访问过
        int nextRow = row + direct[steering][0], nextCol = col + direct[steering][1];
        // 如果是边界或者已经访问过, 则顺时针旋转到下一个方向
        if (nextRow < 0 || nextRow >= n || nextCol < 0 || nextCol >= n || result[nextRow][nextCol] != 0) {
            steering = (++steering) % 4;
        }
        // 确定真实的下一个位置
        row = row + direct[steering][0];
        col = col + direct[steering][1];
    }
    return result;
}

/**
 * 按层遍历,确定每一层的四个角,并且每一层都是先从左上到右上,从右上到右下,从右下到左下,从左下到左上,形成循环
 *
 * @param n 二维数组的长度
 * @return 二维数组
 */
public static int[][] generateMatrix2(int n) {
    int[][] result = new int[n][n];
    int num = 1;
    int left = 0, right = n - 1, top = 0, bottom = n - 1;
    while (left <= right && top <= bottom) {
        for (int col = left; col <= right; col++) {
            result[left][col] = num;
            num++;
        }
        for (int row = top + 1; row <= bottom; row++) {
            result[row][right] = num;
            num++;
        }
        for (int col = right - 1; col >= left; col --) {
            result[bottom][col] = num;
            num++;
        }
        for (int row = bottom - 1; row > top; row --) {
            result[row][left] = num;
            num++;
        }
        left ++;
        right --;
        top ++;
        bottom --;
    }
    return result;
}