给定一个正整数 n,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3
输出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
本题类似于打印图案一类的题,关键在于找到二维数组下标i和j的变化规律:
以n=3为例,将矩阵从1填到9,观察(i,j)的变化:
(0,0)——(0,1)——(0,2)——(1,2)——(2,2)——(2,1)——(2,0)——(1,0)——(1,1)
大致规律就是,i不变,j增加到n;然后j不变,i增加到n;然后i不变,j减小到0;然后j不变,i减小到0。这样的循环。那么我们可以设置几个变量来控制这个过程:
变量flag,用来控制是i变化还是j变化,flag=1表示j变化,flag=0表示i变化,用flag=1-flag来改变flag的值,初始为1。
变量as和bs:这一对变量用来改变i和j的值,使他们增加或减小,as和bs初始为1,用as=-as和bs=-bs来改变他们的值。
变量a和b:分别表示i和j,初始都为0。
变量i:用来从1到n*n循环,用上面几个变量来控制二维数组下标,将i填入二维数组中。
循环开始后,首先判断flag的值,来决定a变化还是b变化。然后填数res[a][b]=i。然后用a+=as或b+=bs来改变a或b的值。改变后,就需要判断边界条件,如果碰到了边界或者下一个位置已经填上数了,那么我们就该改变as和bs和flag的值,即“拐弯”了。改变as和bs的方向,即as=-as,bs=-bs。因为我们是先改变a或b的值,再进行边界判断的,所以需要将此时的a或b回退一位,即a+=as或b+=bs。然后改变flag的值:flag=1-flag。最后也是最关键的一点,就是要将另一个变量a或b的值前进一位,防止覆盖掉刚刚填上的数。代码如下:
public static int[][] generateMatrix(int n) {
int[][] res = new int[n][n];
int a = 0, b = 0, as = 1, bs = 1, flag = 1;
for (int i = 1; i <= n * n; i++) {
if (flag == 1) {
res[a][b] = i;
b += bs;
if (b == n || b == -1 || res[a][b] != 0) {
a += as;
bs = -bs;
b += bs;
flag = 1 - flag;
}
} else {
res[a][b] = i;
a += as;
if (a == n || a == -1 || res[a][b] != 0) {
b += bs;
as = -as;
a += as;
flag = 1 - flag;
}
}
}
return res;
}