[Day 14]螺旋矩阵
今天我们来讲一道数组关于螺旋矩阵的题型,主要是要理清边界值,起始位置,以及循环的条件等
力扣链接 59. 螺旋矩阵 II
给你一个正整数 n ,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
提示:
1 <= n <= 20
思路
首先我们看题说一个正整数n生成一个1到n^2的所有元素,并排成矩阵。那么假如给一个正整数n=4,一共16个元素。假如给一个正整数n=3,一共9个元素。本题是面试中常考的,很多人一看到这个题就会很蒙,转转转不知道转到最后怎末写代码,遍历一行会,遍历一个矩阵就无从下手,其实我们之前讲过二分查找的题型中说到,要坚持循环不变量原则,此题亦是,处理边界就是左闭右开的处理和左闭右闭的处理。我以左闭右开来讲解。左闭右开,我们每个遍历都不取最后一个值。我们一个一个拆解出来:
从左到右遍历
从上到下遍历
从右到左遍历
从下到上遍历
那么代码分步骤如下:
1.因为是矩阵,有多行多列。所以我们定义一个二维数组来初始化数组。
vector<vector<int>> nums(n, vector<int>(n, 0));//声明二维变量,第一个n是存了n个元素,后面的是给n个元素初始化为0
2.使用startx,starty初始化起始位置和终止位置。
n给了几,我们需要算出转了几圈,就是n/2。一直循环,因为转完一圈圈数会缩小。使用一个count来计数就是遍历我们的123456789
int startx = 0;
int starty = 0;
int loop = n / 2;
int count = 1;
3.如果是奇数圈,会剩下一个数进不了while循环,我们直接在最后把它的值计数到数组里。
int mid = n / 2;//假如n为3,mid就=1
if (n % 2) {
nums[mid][mid] = count;//mid[1][1],就是中间位置直接赋值。
}
4.进入四个遍历,在遍历前,要注意赋值变量i,j为起始位置和终止位置进行遍历。
i=startx;
j=starty;
// 从左到右(左闭右开)
for (j; j < n - offset; j++) {//offset为记录减少的圈数
nums[i][j] = count;//i,j的值赋值给count计数
count++;
}//j等于n-offset就退出
// 从上到下(左闭右开)
for (i; i < n - offset; i++) {//i此时从j开始
nums[i][j] = count++;
}
// 从右到左(左闭右开)
for (; j > starty; j--) {
nums[i][j] = count++;
}
// 从下到上(左闭右开)
for (; i > startx; i--) {
nums[i][j] = count++;
}
5.遍历完一圈,第二圈的时候,起始位置终止位置要往前移动一位,offset也加加
startx++;
starty++;
offset++;
6.最后返回数组
return nums;
完整代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> nums(n, vector<int>(n, 0));//定义一个二维数组
int startx = 0;
int starty = 0;//定义初始化位置和终止位置
int loop = n / 2;//循环继续的条件
int offset = 1;//比如3-1=2,n<2
int count = 1;//计数
int mid = n / 2;
int i,j;//定义i,j进行for循环
while (loop--) {
i=startx;//i,j赋值为起始位置,终止位置
j=starty;
// 从左到右(左闭右开)
for (j; j < n - offset; j++) {
nums[i][j] = count;
count++;
}
// 从上到下(左闭右开)
for (i; i < n - offset; i++) {
nums[i][j] = count++;
}
// 从右到左(左闭右开)
for (; j > starty; j--) {
nums[i][j] = count++;
}
// 从下到上(左闭右开)
for (; i > startx; i--) {
nums[i][j] = count++;
}
startx++;//每走一圈起始位置终止位置向里圈移动一位
starty++;
offset++;//变大就会缩小范围
}
if (n % 2) {//如果是奇数,直接把中间值计数
nums[mid][mid] = count;
}
return nums;//返回矩阵
}
};
总结
这道题主要是**画图**理解这个循环遍历和条件的**左闭右开**范围,在while的大循环条件下,使用四个for循环遍历,并将它们进行计数,要考虑好j等于starty时,终止条件,i表示行,是不变的,列一直在变等等。好啦,看到这里,希望我的理解对你有所帮助~