螺旋矩阵

螺旋矩阵Ⅱ

题目链接

代码随想录的解答非常清晰,这里贴上:

相信很多同学刚开始做这种题目的时候,上来就是一波判断猛如虎。

结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。

求解本题一定要坚持循环不变量原则

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

附上源地址:https://programmercarl.com/0059.%E8%9E%BA%E6%97%8B%E7%9F%A9%E9%98%B5II.html#%E6%80%9D%E8%B7%AF

代码:

class Solution {
	public:
		vector<vector<int>> generateMatrix(int n) {
			vector<vector<int>> Matrix(n,vector<int>(n,0)); //矩阵初始化0
			int startx = 0,starty = 0; //每一圈的起始位置
			int loop = n/2; //螺旋的圈数
			int offset = 1; //每次螺旋的长度缩短量
			int count = 1; //给矩阵赋值
			int mid = n/2; //若n为奇数,需要单独给矩阵的中心点赋值
			int i,j;
			while(loop--) {  //一个螺旋圈要进行四次循环,分别是从左到右,从上到下,从右到左,从下到上
				i = startx;
				j = starty;
				//每一条边的赋值保持左闭右开
				for(; j < n - offset; j++) {	//从左到右
					Matrix[i][j] = count++;
				}
				for(; i < n - offset ; i++) {	//从上到下
					Matrix[i][j] = count++;
				}
				for(; j > starty; j--) {	//从右到左
					Matrix[i][j] = count++;
				}
				for(; i > startx; i--) {	//从下到上
					Matrix[i][j] = count++;
				}
				startx++;
				starty++;
				offset += 1;
			}
			if(n % 2) {
				Matrix[mid][mid] = count; 
			}
			return Matrix;
		}
};

相关题目:螺旋矩阵

题目链接

这道题我想用同样的思路解答,而因为这道题行数不等于列数,我就修改从左到右和从上到下的循环截止条件,即:

int m = matrix.size(); //矩阵的行数
int n = matrix[0].size(); //矩阵的列数 
for(; j < n - offset; j++) {	//从左到右
    seq.push_back(matrix[i][j]);
}
for(; i < m - offset ; i++) {	//从上到下
    seq.push_back(matrix[i][j]);
}

并且,当行数为奇数时,会剩下最中间一行没有读取,所以加上以下代码:

if(m % 2) {     //当行数为奇数时,需要单独读取矩阵mid的行数 
    for(j = starty; j < n - offset ; j++) {
	seq.push_back(matrix[mid][j]);
    }
}

但是,遇到了如下问题:

1、当行数为奇数时,最后读取最中间一行的代码存在问题,不能读取完所有的矩阵元素。

在试图通过下列代码解决1问题后:

  //当行数等于列数时,因为左闭右开的缘故,会漏下螺旋的最后一个元素
            if(m == n) {
                seq.push_back(matrix[mid][mid]);
            }

2、又发现当行数为1或列数为1时,会发生重复读取的问题。

那单独对这两种情况进行处理:

if(m == 1 || n == 1) {
    for(i = 0; i < m; i++) 
        for( j = 0; j < n; j++) {
            seq.push_back(matrix[i][j]);
        }
    }
}

3、测试后,发现1“当行数为奇数时,最后读取最中间一行的代码存在问题,不能读取完所有的矩阵元素”的描述有误。

因为每一次螺旋,并不能保证从完整经历完从左到右,从上到下,从右到左,从下到上四个步骤,这是与螺旋矩阵Ⅱ不同的地方。

如果仍然用之前的代码,会出现很多错误。

修修补补几次后,我要放弃这种算法!

学习了leetcode-YouLookDeliciousC的题解思想:

定义四个边界,上下左右,每从左到右,从上到下,从右到左,从下到上过一次,就修改边界,当边界交错,即螺旋完成。

代码:

class Solution {
	public:
		vector<int> spiralOrder(vector<vector<int>>& matrix) {
			vector<int> seq; //返回的矩阵序列 
			int m = matrix.size(); //矩阵的行数
			int n = matrix[0].size(); //矩阵的列数 
			int u = 0, d = m -1, l = 0, r =n - 1; //定义矩阵的上下左右  
			int i,j;
			while(true) { 
				for(i = u, j = l; j <= r; j++) {	//从左到右
					seq.push_back(matrix[i][j]);
				}
				if(++u > d) break;  //修改上边界,若上边界大于下边界,则遍历完成 
				for(i = u; i <= d ; i++) {	//从上到下
					seq.push_back(matrix[i][r]);
				}
				if(--r < l) break;  //修改右边界 
				for(j = r; j >=l ; j--) {	//从右到左
					seq.push_back(matrix[d][j]);
				}
				if(--d < u) break; //修改下边界 
				for(i = d; i >= u; i--) {	//从下到上
					seq.push_back(matrix[i][l]);
				}
				if(++l > r) break; //修改左边界 
			}
			return seq;
		}
};

这个代码看着太清爽啦!

原题解:C++ 详细题解

后续

再思考了一下后突然发现,螺旋次数loop并不能用行数m除以2,而是min(m,n)/2(n是列数),这样,当min(m,n)为奇数时,会留下一行或一列没有读取,最后单独对这一行或列单独操作也可。

然后通过啦!

代码:

class Solution {
	public:
		vector<int> spiralOrder(vector<vector<int>>& matrix) {
			vector<int> seq; //返回的矩阵序列 
			int m = matrix.size(); //矩阵的行数
			int n = matrix[0].size(); //矩阵的列数 
			int startx = 0,starty = 0; //每一圈的起始位置
			int loop = min(m,n)/2; //螺旋的圈数
			int offset = 1; //每次螺旋的长度缩短量
			int i,j;
			while(loop--) {  //一个螺旋圈要进行四次循环,分别是从左到右,从上到下,从右到左,从下到上
			    i = startx;
			    j = starty;
			    //每一条边的赋值保持左闭右开
			    for(; j < n - offset; j++) {	//从左到右
				   seq.push_back(matrix[i][j]);
//				    vector<int>::iterator it = seq.end();
//				    seq.insert(it,matrix[i][j]); 
			    }
			    for(; i < m - offset ; i++) {	//从上到下
				    seq.push_back(matrix[i][j]);
//				    vector<int>::iterator it = seq.end();
//				    seq.insert(it,matrix[i][j]); 
				    }
			    for(; j > starty; j--) {	//从右到左
				    seq.push_back(matrix[i][j]);
//				    vector<int>::iterator it = seq.end();
//				    seq.insert(it,matrix[i][j]); 
			    }
			    for(; i > startx; i--) {	//从下到上
				    seq.push_back(matrix[i][j]);
//				    vector<int>::iterator it = seq.end();
//				    seq.insert(it,matrix[i][j]); 
			    }
			    startx++;
			    starty++;
			    offset += 1;
		    }
                //当行数为奇数时,会剩下一行或以列没有读取完
                if(min(m,n) % 2) {
                    for (i = startx, j = starty; i <= m - offset  ; i++) {
                        for (j = starty; j <= n - offset ; j++) {
                            seq.push_back(matrix[i][j]);
                        }   
                    }
                }
			return seq;
		}
};

 

posted @ 2022-09-10 22:08  aya77  阅读(63)  评论(0)    收藏  举报