算法刷题-数组系列-59.螺旋矩阵||
题目描述
给你一个正整数n
,生成一个包含1到 n2所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例:输入3
形象展示:
返回结果: [[1,2,3],[8,9,4],[7,6,5]]
思路
解题难点
这一道题一开始写的比较混乱,思路不难就按照边界和圈圈依次赋值,原因在于难以确定每次循环的不变量是什么,例如是按照每条边一次赋值为一次大的循环,还是每一圈赋值为一次大的循环;以及每一条边赋值到哪一步停止赋值,因为可能会出现上一条边赋值3个数,下一条边赋值2个数,下下下一条边赋值一个数的情况。
解题要点
确定每次循环的不变量原则:每一条边的赋值都遵循左闭右开原则,以n=3为例,只赋值前两个数,第三个数为开,不在赋值区间内,反而是下一条边的起始(因为两条边共用一个顶点)。
这样可以保证每一条边的赋值个数是一样的,互相之间没有重叠。
面临进入下一圈赋值时,仍然是左闭右开原则,并且上一圈的赋值和下一圈的赋值互不影响。(当赋值只剩一个点时,就直接填入尾数)
需要的变量
输入的数字n
转圈轮次(不包含中心点):其与n/2有关
一个矩阵中的坐标指针,代表当前赋值的位置x和y
本轮赋值需要左闭右开的开的阈值,即以第一轮为例,n=3是1,n4的第二轮是2
代码
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> result(n,vector<int>(n, 0));
int num = 1;
int startx = 0;
int starty= 0;
int edgeLengthDe=1;
int randTimes = n/2; //执行轮次
while(randTimes--){
//这个是定义这一圈写入的起始坐标,第一轮[0][0],第二轮[1][1]
int i = startx;
int j = starty;
//依据左闭右开原则,即同一边最左边加入,同一边最右边的作为下一条边的开头
//开始从左到右填充,不包含这一行的最右一个(下一个for的起始)
for(;j<n-edgeLengthDe;j++){
result[i][j] = num++;
}
//从上到下填充,左闭右开,不包含这列最下一个(下一个for的起始)
for(;i<n-edgeLengthDe;i++){
result[i][j] = num++;
}
//从右到左填充,左闭右开。不包含这行最左一个(下一个for的起始)
for(;j>starty;j--){
result[i][j] = num++;
}
//从下到上填充。不包含这一列最上一个
//(也就是[0][0]或者[1][1],这样刚好把一圈填满,下一轮次的边长不变原则再重新制定)
for(;i>startx;i--){
result[i][j] = num++;
}
//下一圈的起始位置要从类似[0][0]->[1][1]
startx++;
starty++;
edgeLengthDe++; //下一圈的边长减少数量要加1,因为已经填过一圈了
}
if(n%2)//即如果n%2==1就是圈跑满了还剩下最后一个中心没填的情况
{
int mid = n/2;
result[mid][mid]=num;
}
return result;
}
};