59. 螺旋矩阵 II
题目:
要求:
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
答案:
两种解法:
一种用计算机模拟顺时针旋转的效果,这种方法看起来容易,做起来并没有那么容易,我开始就用这个思路做的,结果发现写不出来,看了下题解,才写出来,我写不出来的点就是在旋转的地方没有做到,我想着每一个点都是一种情况,没有总结出通用的旋转情况,并且没有使用下一个位置来做旋转,而是判断当前位置来做旋转,这是其一;其二是每一个定点旋转其实规律是相同的,官方题解给出了一个二维数组就非常巧妙,单独定义了一个旋转点来作为二维数组的横坐标,横坐标就分别代表了向右、向下、向左、向上,思路简单,代码不好写呀。
第二种是层级思维,每次遍历一层,也就是最外面一层,这个时候不需要考虑边界,只要定义四个定点就行,在每遍历一层,修改四个定点就可以,四个定点分别是每一层开始的横坐标(left)、纵坐标(top)、结束的横坐标(right)、结束的纵坐标(bottom),其实开始的横纵坐标一定是相等的,用一个变量也可以,方便理解还是分开表示,这样每遍历一层,坐标变化是 left + 1
、 top + 1
、 right - 1
、bottom - 1
,循环结束的条件就是 left ≤ right
,top ≤ 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;
}