目录
题目
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
示例 1:
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1 输出:[[1]]
思路
相当于是一个绕正方形,首先弄明白环绕方式,然后它的关键在于正方形四个角的处理。
想法遵循二分法的循环不变量原则。我们选择第一行从左到右,接着从上到下,再从右到左,最后从下到上;一层循环结束后进行第二层......这里采用左闭右开,就是有四个角,每一行都是包含开头那个角,另外一个角等处理旁边那条边的时候再进行,这样有一个规则就不会弄混了。
同一个颜色代表同一次处理
代码
class Solution {
public int[][] generateMatrix(int n) {
int starty=0,startx=0;//把他想成一个数组的排列,有x有y,startx表示行的第一个,starty表示列的第一个
int i,j;//通常我们习惯把数组表示成a[i][j],所以这里i表示行,j表示列
int offset=0;//这个表示循环次数
int count=1;//因为这个数组排列是从1到n的平方,所以我们这里是1
int [][] res=new int [n][n];//定义一个数组让他是一个正方形
while(offset++<n/2){//这里要先加,不能offset赋值为0然后这里直接进循环后面才++,这样会造成正方形角计算的混乱,以及为什么是n/2,画一个图就知道了,它表示的是循环的次数
for(j=starty;j<n-offset;j++){//这是第一行从左到右,j从列的第一个开始,然后第一个元素的索引是0,假如n为4,那么最后那个数字的索引为3,然而不能包括这个数字(原因在思路中),所以这里是n-offset,offset为1,j++让它往后移遍历
res[startx][j]=count++;//这里startx为0,就表示给第一行的赋值了
//最后这里结束是j指向一行中最后一个元素
}
for(i=startx;i<n-offset;i++){//这是从上到下的情况,i从第一行开始,然后情况同上一个
res[i][j]=count++;//上一个for中j指向一行中最后一个元素,所以这里直接给[i][j]赋值了
//这里结束时i指向的是最后一列最后一行的元素
}
for(;j>=offset;j--){//这是从后往前的情况,由于第一次循环j指向一行中最后一个元素,所以这里不需要再给初始值了,然后要包括最后一行的第一个元素,所以是>=
res[i][j]=count++;
}for(;i>=offset;i--){//这是从下往上的情况,由于循环i指向的是最后一行的元素,所以这里不需要再给初始值,其余同上
res[i][j]=count++;
}
//到这里第一圈的循环就结束了但是它可能会有第二圈,第二圈时列和行的起始位置都需要改变,以及减的offset也是,所以再次进入循环
starty++;
startx++;
}
if (n % 2 == 1) {//如果给的n为奇数,最后剩下的是最中间的元素,直接给他赋值即可
res[startx][starty] = count;
}
return res;
}
}
注意:
为啥循环是:
for(;j>=offset;j--)而不是>=starty呢
>=offset就不会包括那个最后一行第一个角了(也就是示例中数字7的位置),这样遵循了循环不变量原则,然而如果是另外一种情况的话,拿第一圈循环为例,相当于是>=0,这同样会包括它,就违背了这个原则