一入循环深似海 | LeetCode:59.螺旋矩阵II
思路来自:代码随想录-59.螺旋矩阵II
给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3
输出:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]
本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。
结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。
而求解本题依然是要坚持循环不变量(二分法也用到过)原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
代码执行需要遵循规则,要不就太乱了,在设计代码前先要确定规则。
此题遵循的是循环不变量原则,和左闭右开原则。这样确保了代码的规范性。
以下是题目的代码:
int main() {
//规定初始值
int start =1;
int n=0;
scanf("%d",&n);
int a[n][n];
int startx=0,starty=0;
int offset = 1 ;
//要转的圈数
int quan =n/2;
int x=0,y=0;
while (quan--) {
//一圈一圈转,遵循循环不变量和[l,r)
//上面部分
//每次循环重置起始位置
//offset 每次旋转都会少一个所以到这里停下 注意是左闭右开 的 控制每一圈收缩的程度 即:转了几圈
for (x =startx;x<n-offset;x++ ) {
a[starty][x]=start++;
}
//右边部分
for (y=starty;y<n-offset;y++) {
a[y][x]=start++;
}
//下面部分
for (;x>startx;x--) {
a[y][x]=start++;
}
for (;y>starty;y--) {
a[y][x]=start++;
}
//循环结束后更新起始位置 按照对角线移动
startx++;
starty++;
offset++;
}
//处理奇数的情况
if (n%2==1) {
a[n/2][n/2]=start;
}
//打印输出结果
for (int i = 0; i <n; i++) {
for (int j = 0; j <n; j++) {
printf("%6d ",a[i][j]);
}
printf("\n");
}
return 0;
}
问题:
老师说:就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。
之前写代码就是先遍历第一行,第一行完了之后从第二行开始遍历,而没有遵循左闭右开原则,导致了一会左开右闭,一会左闭右闭。
边界太混乱。
还是建议多练习,多刷题。
54. 螺旋矩阵
我的代码:
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector <int> a;
//获取数组维度
int m = matrix.size();
int n = matrix[0].size();
int quan = m/2+1;
//定义每次循环的起点和终止位置
//每次循环都是一个新的开始,不要想成和上一个连续
//我们只需要找规律就可以了
//圈数是 n/2 原因是 转一圈后消耗两行
int startx=0,starty=0;
int x=0,y=0;
//定义 offset 我么旋转的范围是 [) "左闭右开"
int offset = 1;
while(quan--){
//模拟旋转过程 从上边旋转
for(x=startx;x<n-offset;x++){
a.push_back(matrix[starty][x]);
}
//模拟右边旋转
for(y=starty;y<m-offset;y++){
a.push_back(matrix[y][x]);
}
//模拟下面旋转
for(;x>startx;x--){
a.push_back(matrix[y][x]);
}
for(;y>starty;y--){
a.push_back(matrix[y][x]);
}
offset += 1;
startx++;
starty++;
}
if(n%2!=0){
a.push_back(matrix[y][x]);
}
return a;
}
};
修正后的代码:
class Solution {
public:
vector<int> spiralOrder(vector<vector<int>>& matrix) {
vector<int> a;
//获取数组维度
int m = matrix.size();
int n = matrix[0].size();
int quan = min(m, n) / 2; // 修正:圈数应该是行和列的最小值除以2
//定义每次循环的起点和终止位置
int startx = 0, starty = 0;
int x = 0, y = 0;
//定义 offset
int offset = 1;
while(quan--){
//模拟旋转过程 从上边旋转
for(x = startx; x < n - offset; x++){
a.push_back(matrix[starty][x]);
}
//模拟右边旋转
for(y = starty; y < m - offset; y++){
a.push_back(matrix[y][x]);
}
//模拟下面旋转
for(; x > startx; x--){
a.push_back(matrix[y][x]);
}
//模拟左边旋转
for(; y > starty; y--){
a.push_back(matrix[y][x]);
}
offset += 1;
startx++;
starty++;
}
// 处理剩余的中心行或列
if(m <= n && m % 2 == 1){ // 行数为奇数,剩余一行
for(int i = startx; i <= n - offset; i++){
a.push_back(matrix[starty][i]);
}
} else if(n < m && n % 2 == 1){ // 列数为奇数,剩余一列
for(int i = starty; i <= m - offset; i++){
a.push_back(matrix[i][startx]);
}
}
return a;
}
};
关键修改:
- 圈数计算:
quan = min(m, n) / 2- 考虑行和列的最小值 - 中心处理:分别处理剩余一行或一列的情况
- 边界修正:在最后的循环中使用
<=来包含边界元素