螺旋矩阵II
题目
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
思路一:
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
由外向内一圈一圈这么画下去。
注意循环不变量:每行/列不走满,开头留一格或结尾留一格
重点:判断碰头,若下一位不为零,则继续按照之前的方向前进,否则转向
代码一(每个方向的行走规则各写一个)
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n,vector<int>(n,0));//创建二维数组
int i=0,j=0;
int cnt=1;
res[0][0] = 1;
while(cnt<n*n){
while(j<n-1 && res[i][j+1]==0)res[i][++j] = ++cnt;
while(i<n-1 && res[i+1][j]==0)res[++i][j] = ++cnt;
while(j>0 && res[i][j-1]==0)res[i][--j] = ++cnt;
while(i>0 && res[i-1][j]==0)res[--i][j] = ++cnt;
}
return res;
}
};
代码二(利用方向向量转向)
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int dx = 0, dy = 1; //方向向量
int x = 0, y = 0;
for (int i = 1; i <= n * n; ++i) {
res[x][y] = i;
//判断下一位是否已经有数字,注意加n再取模,防止数组越界
if (res[(x + dx + n) % n][(y + dy + n) % n] != 0) {
//若有数字,则向右转向,令(dx,dy)-->(dy,-dx)
int tmp = dy;
dy = -dx;
dx = tmp;
}
//依据方向向量移动
x += dx;
y += dy;
}
return res;
}
};
思路二:
这里的方法不需要记录已经走过的路径,所以执行用时和内存消耗都相对较小
- 首先设定上下左右边界
- 其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界
- 判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案
- 若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理
- 不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案
代码三(删除走过的边)
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int up=0,down=n-1,l=0,r=n-1;//上边界up,下边界down,左边界l,右边界r
int cnt = 1;
int i=0,j=0;
while(true){
for(i=up,j=l;j<=r;j++)res[i][j]=cnt++;
if(++up > down)break;
for(i=up,j=r;i<=down;i++)res[i][j]=cnt++;
if(--r < l)break;
for(i=down,j=r;j>=l;j--)res[i][j]=cnt++;
if(--down < up)break;
for(i=down,j=l;i>=up;i--)res[i][j]=cnt++;
if(++l > r)break;
}
return res;
}
};