这一篇记录代码随想录,与螺旋矩阵相关的问题,以leetcode 第59.螺旋矩阵II为例。
题目:给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
Carl哥代码随想录中,通过按层模拟解决:
- 填充上行,从左到右
- 填充右列,从上到下
- 填充下行,从右到左
- 填充左列,从下到上
关键点就是:每次填充行或列,一定要坚持左闭右开的原则。即每一条边从头开始遍历到尾的前一个元素,不遍历尾。
如下图所示,把拐角交给新的边来处理:
之所以坚持左闭右开,是为了固定一个规则。否则,若是横的边从头遍历到尾,竖的边掐头去尾,对于每一条边的遍历规则就不一样了。并且,在下面代码实现中,用左闭右开的原则,可以感受到代码的整洁美。
int startx = 0; // 每一圈开始遍历元素的x坐标
int starty = 0; // 每一圈开始遍历元素的y坐标
int offset = 1; // 初始是第1圈
int value = 1; // 填充的数值
int loop = n / 2; // 需要遍历loop圈。这个可以画图推一下,奇数维loop圈后只剩中间一个元素未遍历,偶数维loop圈后全部遍历完毕
int[][] ans = new int[n][n];
while (loop-- > 0) {
int i = startx;
int j = starty;
for ( ; j < n - offset; j++) // 上行,从左到右,左闭右开
ans[i][j] = value++;
for ( ; i < n - offset; i++) // 右列,从上到下,左闭右开
ans[i][j] = value++;
for ( ; j > starty; j--) // 下行,从右到左,左闭右开
ans[i][j] = value++;
for ( ; i > startx; i--) // 左列,从下到上,左闭右开
ans[i][j] = value++;
startx++;
starty++;
offset++;
}
if (n % 2 == 1) { // 奇数维的矩阵,中间那个元素额外填充
ans[startx][starty] = value;
}
return ans;
——————————————————————————————————————————
代码随想录中,推荐的相似题目是:54.螺旋矩阵、剑指Offer 29.顺时针打印矩阵。
螺旋矩阵:
螺旋矩阵II中的矩阵行列数相等,是一个方阵,而螺旋矩阵中的矩阵就是普遍的矩阵,行列数不定。因此,螺旋矩阵II 是螺旋矩阵的一个特殊形式。
同样,坚持左闭右开的原则。不同的是,这里的矩阵行列数可能不一致,那么,一些细节需要改变。
首先,是while循环遍历的圈数,即loop的值。显然,loop的值应该是min(row, column) / 2,即行数和列数 较小值除以2,可以画图推导一下。
其次,是当min(row, column) 是奇数时,遍历完loop圈后,会剩下中间一行 或一列没有遍历,此时需要额外遍历,就如同螺旋矩阵II 中需要额外填充中间那个元素一样。
int m = matrix.length; // 矩阵行数
int n = matrix[0].length; // 矩阵列数
int startx = 0;
int starty = 0;
int offset = 1;
int loop = Math.min(m, n) / 2;
List<Integer> ans = new ArrayList<>();
while (loop-- > 0) {
int i = startx;
int j = starty;
for ( ; j < n - offset; j++) // 上行
ans.add(matrix[i][j]);
for ( ; i < m - offset; i++) // 右列
ans.add(matrix[i][j]);
for ( ; j > starty; j--)
ans.add(matrix[i][j]); // 下行
for ( ; i > startx; i--)
ans.add(matrix[i][j]); // 左列
startx++;
starty++;
offset++;
}
if (Math.min(m, n) % 2 == 1) { // 行数和列数 较小值是奇数,需要额外遍历
if (m < n) {
for ( ; starty < n - offset + 1; starty++) // 行数<列数,遍历一行
ans.add(matrix[startx][starty]);
} else {
for ( ; startx < m - offset + 1; startx++) // 行数>=列数,遍历一列
ans.add(matrix[startx][starty]);
}
}
return ans;
顺时针打印矩阵:
这一题相较于螺旋矩阵,只需要注意题目中的边界限制即可,他允许行数或列数为0。