六、螺旋矩阵Ⅱ
题目:
给你一个正整数 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,结果是n*n的矩阵)
- 如果n是偶数,那么转n/2圈;
- 如果n是奇数,那么转n/2圈后,还留下了中间的位置,我们就进行单独赋值,把最后遍历的一个数给中间位置即可。
代码讲解:左闭右开
//定义一个变量,控制循环次数(转圈次数)
int loop = 0;
//定义一个二维数组矩阵,存放1到n^2
int[][] nums = new int[n][n];
//由于起始位置每一圈都是要变的,所以定义变量来存放起始位置
int startx = 0, starty = 0;
//由于终止位置每一圈也都是要变化的,所以需要定义一个变量来控制终止位置
int offset = 1;
//定义一个变量用来填充数字,从1到n^2
int count = 1;
// 循环转圈,一般坐标用 (i , j) 表示,i表示行,j表示列
while(loop++ < n / 2) { //判断完边界后,loop从1开始
// 遍历第一条边(上面横边从左到右)例如n=4,最后一个位置下标就是3,j<3则最后一个位置就不会被遍历到了
for(int j = starty; j < n - offset; j++) {
// startx是固定的,因为是这一圈的起始位置(行数)
nums[startx][j] = count++; //将count赋给数组固定位置后,再将count+1
}
//遍历第二条边(右侧竖边从上到下)正方形,边界条件是一样的
for(int i = startx; i < n - offset; i++) {
//这里的j在上面的循环结束后,就已经等于n-offset了,指向了上一条边最后一个元素
// 遍历第二条边的时候,j的值是不变的,表示列值
nums[i][j] = count++;
}
//遍历第三条边(下面横边从右到左),j已经等于n-offset了,不需要初始化了
for(; j > starty; j--) {
nums[i][j] = count++;
}
//遍历第四条边(左侧由下到上),i已经等于n-offset了,不需要初始化了
for(; i > startx; i--) {
nums[i][j] = count++;
}
//这样就已经转完了最外侧的一圈,开始转里面那一圈
//每转一圈起始位置应该加1,缩小了一圈
startx++;
starty++;
//控制终止位置的offset,每转一圈应该+1,因为往里缩了一圈
offset++;
}
//转完以后,还需要判断n是否为奇数
if(n % 2 == 1) {
//此时startx和starty已经走到了中间的位置
nums[startx][starty] = count;
}
总结:
求解本题依然是要坚持循环不变量原则。
模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右到左
- 填充左列从下到上
由外向内一圈一圈这么画下去。
例如:按左闭右开原则来填充
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。
如果是奇数,最后会单独填充中间那个位置。
这也是坚持了每条边左闭右开的原则。
题解:

1106

被折叠的 条评论
为什么被折叠?



