内容介绍
给你一个正整数
n
,生成一个包含1
到n2
所有元素,且元素按顺时针顺序螺旋排列的n x n
正方形矩阵matrix
。示例 1:
输入:n = 3 输出:[[1,2,3],[8,9,4],[7,6,5]]示例 2:
输入:n = 1 输出:[[1]]提示:
1 <= n <= 20
完整代码
class Solution {
public int[][] generateMatrix(int n) {
int l = 0, r = n - 1, t = 0, b = n - 1;
int[][] mat = new int[n][n];
int num = 1, tar = n * n;
while(num <= tar){
for(int i = l; i <= r; i++) mat[t][i] = num++; // left to right.
t++;
for(int i = t; i <= b; i++) mat[i][r] = num++; // top to bottom.
r--;
for(int i = r; i >= l; i--) mat[b][i] = num++; // right to left.
b--;
for(int i = b; i >= t; i--) mat[i][l] = num++; // bottom to top.
l++;
}
return mat;
}
}
思路详解
代码功能
这段代码定义了一个名为Solution
的类,其中包含一个名为generateMatrix
的方法。该方法用于生成一个按顺时针顺序填充的n阶矩阵,矩阵中的元素从1开始递增,直到n*n。
思路详解
-
初始化边界变量
l
和r
分别表示矩阵的左边界和右边界,初始值分别为0和n-1。t
和b
分别表示矩阵的顶部边界和底部边界,初始值分别为0和n-1。
-
创建矩阵
- 使用
new int[n][n]
创建一个n阶矩阵mat
,用于存储填充的元素。
- 使用
-
初始化填充变量
num
表示当前要填充的数字,初始值为1。tar
表示填充的目标值,即n*n。
-
循环填充矩阵
- 使用
while
循环,当num
小于等于tar
时,继续填充矩阵。
- 使用
-
按顺时针顺序填充矩阵
- 从左到右填充顶部行:使用
for
循环,从左边界l
到右边界r
,填充顶部行mat[t][i]
,并将num
递增。 - 从上到下填充右侧列:使用
for
循环,从顶部边界t
到底部边界b
,填充右侧列mat[i][r]
,并将num
递增。 - 从右到左填充底部行:使用
for
循环,从右边界r
到左边界l
,填充底部行mat[b][i]
,并将num
递增。 - 从下到上填充左侧列:使用
for
循环,从底部边界b
到顶部边界t
,填充左侧列mat[i][l]
,并将num
递增。
- 从左到右填充顶部行:使用
-
更新边界
- 在每完成一轮填充后,更新边界变量:顶部边界
t
向下移动一位(t++
),右边界r
向左移动一位(r--
),底部边界b
向上移动一位(b--
),左边界l
向右移动一位(l++
)。
- 在每完成一轮填充后,更新边界变量:顶部边界
-
返回填充后的矩阵
- 当
num
大于tar
时,循环结束,返回填充好的矩阵mat
。
- 当
总结
这段代码通过不断缩小矩阵的边界,并在每轮循环中按照顺时针顺序填充矩阵,最终生成一个按顺时针顺序递增的n阶矩阵。整个算法的时间复杂度为O(n^2),空间复杂度为O(n^2),适用于需要生成螺旋矩阵的场景
知识点精炼
矩阵初始化
- 使用
int[n][n]
声明并初始化一个二维数组,用于存储螺旋矩阵的元素。
2. 边界控制
- 使用四个变量
l
(左边界)、r
(右边界)、t
(上边界)、b
(下边界)来控制矩阵的填充范围。
3. 循环填充
- 使用
while
循环,条件为当前填充数字num
小于等于矩阵元素总数tar
(即n*n)。
4. 顺时针填充顺序
- 顶部行:从左到右填充,更新上边界
t
。 - 右侧列:从上到下填充,更新右边界
r
。 - 底部行:从右到左填充,更新下边界
b
。 - 左侧列:从下到上填充,更新左边界
l
。
5. 边界收缩
- 在每轮填充后,相应地调整边界变量的值,以缩小下一次填充的范围。
6. 返回结果
- 当填充完毕,返回填充好的二维数组
mat
。
7. 算法效率
- 时间复杂度:O(n^2),因为每个元素都需要填充一次。
- 空间复杂度:O(n^2),用于存储矩阵的二维数组。
8. 编程技巧
- 使用嵌套
for
循环实现矩阵的顺时针填充。 - 通过边界变量的调整,简化循环逻辑,避免复杂的条件判断。
扩展:如何避免填充重复数字
在给出的代码中,填充重复数字通常是由于边界调整不当导致的。为了确保每个数字只填充一次,需要仔细管理边界变量的更新。以下是避免填充重复数字的几个关键点:
-
更新边界前检查:在每轮填充完成后,确保在更新边界之前,新边界不会与旧边界重叠。
-
避免边界重叠:在每次循环结束时,更新边界之前,应该检查是否已经到达了矩阵的极限边界,以避免重叠。
以下是修改后的代码,其中包含了避免填充重复数字的逻辑:
class Solution {
public int[][] generateMatrix(int n) {
int l = 0, r = n - 1, t = 0, b = n - 1;
int[][] mat = new int[n][n];
int num = 1, tar = n * n;
while(num <= tar){
// 从左到右填充顶部行
for(int i = l; i <= r; i++) mat[t][i] = num++;
t++; // 更新上边界
// 从上到下填充右侧列
for(int i = t; i <= b; i++) mat[i][r] = num++;
r--; // 更新右边界
// 确保底部行未被填充
if(t <= b) {
// 从右到左填充底部行
for(int i = r; i >= l; i--) mat[b][i] = num++;
b--; // 更新下边界
}
// 确保左侧列未被填充
if(l <= r) {
// 从下到上填充左侧列
for(int i = b; i >= t; i--) mat[i][l] = num++;
l++; // 更新左边界
}
}
return mat;
}
}
在上述代码中,我添加了两个if
语句来检查在填充底部行和左侧列之前,新的上边界t
是否已经超过了下边界b
,以及新的左边界l
是否已经超过了右边界r
。这样可以确保在矩阵的最后一行和最后一列时不会重复填充。
通过这种方式,我们可以确保每个数字只被填充一次,避免了任何可能的重复填充问题。