59. 螺旋矩阵 II
一、题目
给你一个正整数 n ,生成一个包含 1 到 n*n 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
比如下列格式:
1 2 3
8 9 4
7 6 5
示例 1:
输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]
示例 2:
输入:n = 1
输出:[[1]]
提示:
1 <= n <= 20
二、解法
方法一:switch判断法
思路:(1)初始化一个二维数组,其中元素全部为0,;设置switch的四个判断条件:1、2、3、4分别代表向右、向下、向左、向上。
(2)对这些判断条件进行分析,以3*3矩阵为例,设置i为行指针,j为列指针,首先在初始阶段指针指向的是M[0] [0](i = j = 0),我们通过while循环(这里的判断条件是j < n && v[i] [j] == 0),让指针一直向右走,边走边给数组赋值(v[i] [j]=num++; j++)。到最后i = 0,j = 3,就让 j 回退一位,否则在数组中就越界了。(对应代码中case(1))。
(3)(2)中while循环的跳出主要是因为j = n了,但是到最后也有其他情况,就是在行指针向上走但是列指针不动的时候,往往行指针会碰到已经被赋过值的元素,比如最后从M[2] [0] 往上走时碰到已经被赋过值的 M[0] [0],此时也需要 i 回退一位,即 i++。(对应代码中case(4))。
(4)代码中case(2)和case(3)分别对应向下和向左。
代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> v(n, vector<int>(n, 0));
int flag = 1;
int num = 1;
int i = 0, j = 0;
while (num <= n*n) {
switch (flag) {
case(1)://right
while ( j < n && v[i][j] == 0 ) {
v[i][j] = num++;
j++;
}
flag = 2;
j--;
i++;
break;
case(2)://down
while (i < n && v[i][j] == 0) {
v[i][j] = num++;
i++;
}
flag = 3;
i--;
j--;
break;
case(3)://left
while (j >= 0 && v[i][j] == 0) {
v[i][j] = num++;
j--;
}
flag = 4;
j++;
i--;
break;
case(4)://up
while (i >= 0 && v[i][j] == 0) {
v[i][j] = num++;
i--;
}
flag = 1;
i++;
j++;
break;
}
}
return v;
}
};
方法二:不断框定范围
思路:
(1)对矩阵设置一个范围,拿3*3矩阵举例,先是画一个大框框将矩阵框住(左边界和上边界下标为0,右边界和下边界为n-1=2)
(2)先通过for循环遍历第一行进行赋值,然后上边界下标+1 = 1,这样下一次行指针就不会在上移的时候再碰到被赋值了的第一行了,而是只移动到第二行就结束。
(3)然后列指针循环下移并赋值,意味着最右边一列已经被赋过值,那么右边界下标-1 = 1,那么下一次指针右移的时候就不会指到最后一列了。
(4)其他情况类似。
代码:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> v(n, vector<int>(n, 0));
int num = 1;
int left = 0, right = n-1, up = 0, down = n-1;
while(num <= n*n){
for(int i=left; i<=right; i++){
v[up][i] = num++;
}
up++;
for(int i=up; i<=down; i++){
v[i][right] = num++;
}
right--;
for(int i=right; i>=left; i--){
v[down][i] = num++;
}
down--;
for(int i=down; i>=up; i--){
v[i][left] = num++;
}
left++;
}
return v;
}
};
方法三、类似第二种情况
(1)首先我们知道,给定一个正整数n,形成一个n^2矩阵,会转n/2圈,因此while循环的范围是count<=n/2。
(2)然后我们根据四条边进行遍历,我们采用左闭右开原则,即算上起始点但不算上中点的点。
(3)总数为偶数则不做处理,为奇数则单独给最后那个值赋值。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> v(n, vector<int>(n, 0));
int start_x = 0, start_y = 0;
int offset = 1;
int i = 0, j = 0;//分别代表行号列号
int count = 1, num = 1;//分别代表圏数和值
while(count <= n/2){
//这里必须要给i、j重新赋值,因为后两个for循环需要
i = start_x;
j = start_y;
for(j = start_y; j < n-offset; j++){
v[i][j] = num++;
}
for(i = start_x; i < n-offset; i++){
v[i][j] = num++;
}
for(; j > start_y; j--){
v[i][j] = num++; //第一次循环遍历到左下角结束,(不算左下角的元素)
}
for(; i > start_x; i--){
v[i][j] = num++;
}
start_x++; start_y++; offset++; //缩小圈的范围
count++;
}
if(n % 2 == 1){
v[n/2][n/2] = num; //如果总数为奇数,那么单独给中间那个数赋值
}
return v;
}
};class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> v(n, vector<int>(n, 0));
int start_x = 0, start_y = 0;
int offset = 1;
int i = 0, j = 0;//分别代表行号列号
int count = 1, num = 1;//分别代表圏数和值
while(count <= n/2){
//这里必须要给i、j重新赋值,因为后两个for循环需要
i = start_x;
j = start_y;
for(j = start_y; j < n-offset; j++){
v[i][j] = num++;
}
for(i = start_x; i < n-offset; i++){
v[i][j] = num++;
}
for(; j > start_y; j--){
v[i][j] = num++; //第一次循环遍历到左下角结束,(不算左下角的元素)
}
for(; i > start_x; i--){
v[i][j] = num++;
}
start_x++; start_y++; offset++; //缩小圈的范围
count++;
}
if(n % 2 == 1){
v[n/2][n/2] = num; //如果总数为奇数,那么单独给中间那个数赋值
}
return v;
}
};