题目
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
链接
关键点
-
四角边界的处理
-
条件的处理使当前结点处理还是下一节点处理
遵顼循环不变量原则
不变量即边界条件不变
左闭右开
一条线上有连个结点,该原则的处理方式为,处理第一个结点及边,第二个结点在处理第二条边时处理
实现的细节
-
n为偶数。生成n*n维螺旋矩阵,需要旋转n/2圈(观察和推理所得)
-
n为奇数。(n-1)/2圈,剩余一个元素直接放入螺旋中心,也可以视为(n+1)/2圈
-
每一圈的起始位置。不固定,定义起始坐标点(start x,start y),每一圈的起始位置都不一样
-
第三个结点(右下角),该点的列坐标无需赋初值,处理第二个点的列坐标可以直接用于第三个结点的处理
实现流程
-
定义起始点的坐标位置(startx,starty),遍历元素使用坐标(i,j)表示,圈数loop,更新缩圈后的边界offset
-
while循环(条件是:圈数–)以圈为最小单位控制,四个for循环(条件是:j = starty; j < n - offset; j++)控制每条边上的元素
-
若n为奇数,n^2直接给矩阵中心赋值
流程分析
-
每一圈的开始的坐标由start控制,i,j只负责处理边
-
第二圈相比第一圈,第三圈相比第二圈,起始位置发生了变化,各个角的坐标也发生了变化,因此引入变量loop,offset分别控制圈数,每条边处理的边界坐标
C++
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int startx = 0, starty = 0;
int loop = n / 2;
int mid = n / 2;
int count = 1;
int offset = 1;
int i,j;
while (loop --) {
i = startx;
j = starty;
for (j = starty; j < n - offset; j++) {
res[startx][j] = count++;
}
for (i = startx; i < n - offset; i++) {
res[i][j] = count++;
}
for (; j > starty; j--) {
res[i][j] = count++;
}
for (; i > startx; i--) {
res[i][j] = count++;
}
startx++;
starty++;
offset += 1;
}
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};
Java
class Solution {
public int[][] generateMatrix(int n) {
int start=0;
int res[][]=new int[n][n];
int i,j;
int count=1;
int loop=0;
//控制圈
while(loop++<n/2){
//上边,遵循左闭右开原则
for(j=start;j<n-loop;j++){
res[start][j]=count++;
}
//右边
for(i=start;i<n-loop;i++){
res[i][j]=count++;
}
//下边
for(;j>=loop;j--){
res[i][j]=count++;
}
//左边
for(;i>=loop;i--){
res[i][j]=count++;
}
start++;
}
//n为奇数时,最后一个元素赋给矩阵中心的位置
if(n%2==1){
res[n/2][n/2]=count;
}
return res;
}
}
Java实现分析(与C++不同之处)
受语法限制,实现的思路有所不同
-
loop初值为0
-
使用loop替代offset,引用一个变量控制两种行为
-
后两个for循环条件含由=,是因为C++是与start(while循环中初值为0)比较,Java中的for(;i>=loop;i–)(while循环中loop初值为1),所以判断条件为≥而非>