给你一个正整数
n
,生成一个包含1
到n2
所有元素,且元素按顺时针顺序螺旋排列的n x n
正方形矩阵matrix
。示例 1:
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]示例 2:
输入:n = 1 输出:[[1]]
一、算法思路&&注意事项
- 生成一个 n×n 空矩阵generateMatrix ,随后模拟整个向内环绕的填入过程,模拟顺时针画矩阵的过程是:填充上行从左到右、填充右列从上到下、填充下行从右到左、填充左列从下到上,由外向内一圈一圈这么画下去。
- 可以发现这里的边界条件非常多,在一个循环中,这么多的边界条件,如果不按照固定规则来遍历,那就会十分混乱。因此一圈下来,每一圈要画四条边,这四条边必须按照统一的规则画下来。我这里按照左闭右开的原则进行填充每一条边。如下图所示,箭头代表每次遍历的方向,每次遍历均按照左闭右开的原则进行。
二、代码实现
首先最外层的while循环,我们需要考虑这个n*n的方形矩阵generateMatrix由外到内填充完毕需要多少圈。举个例子:当n为偶数时:如上图所示4*4的矩阵需要2圈才能填充完毕;当n为奇数时:如下图所示3*3的矩阵只需要1圈就能填充完毕,同时对于最内层的中心进行填充只需要设置一个判断条件:
if(n % 2 == 1) generateMatrix[start][start] = count;
填充上行从左到右,此时我们将起点定在(start,start),一开始start=0,offset=1,注意每次填充完一圈后重新开始填充的起点位置都在改变,因此这里的start,offset在每循环填充完一圈后都会start++,offset++;这一部分的代码是:
for(j = start; j < n - offset ; j++){
generateMatrix[start][j] = count++;
}
填充右列从上到下,根据上一次对边的填充和我们遍历的规则,此时填充的位置应该来到(start x,j),因此这部分的代码是:
for(i = start; i < n - offset; i++){
generateMatrix[i][j] = count++;
}
填充下行从右到左,同样的思路,这里不再赘述。
for( ;j > start; j--){
generateMatrix[i][j] = count++;
}
填充左列从下到上
for( ; i > start; i--){
generateMatrix[i][j] = count++;
}
三、完整代码
下面是完整的代码:
class Solution {
public int[][] generateMatrix(int n) {
int offset = 0; // 控制循环次数
int[][] res = new int[n][n];
int start = 0; // 每次循环的开始点(start, start)
int count = 1; // 定义填充数字
int i, j;
while (offset++ < n / 2) { // 判断边界后,loop从1开始
// 模拟上侧从左到右
for(j = start; j < n - offset ; j++){
res[start][j] = count++;
}
// 模拟右侧从上到下
for(i = start; i < n - offset; i++){
res[i][j] = count++;
}
// 模拟下侧从右到左
for( ;j > start; j--){
res[i][j] = count++;
}
// 模拟左侧从下到上
for( ; i > start; i--){
res[i][j] = count++;
}
start++;
}
if (n % 2 == 1) {
res[start][start] = count;
}
return res;
}
}
四、算法时间复杂度分析
时间复杂度:O(n2)
填充时需要由外向内将整个n*n矩阵填满,矩阵有n*n=n2个元素,因此时间复杂度为O(n2)
五、总结
算法本身并不难理解,对边界的考察判断要求比较高,理解本题后可以尝试着试试逆时针的螺旋矩阵如何来写。