目录
题目
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
解法
要在C++中生成一个 n x n
的螺旋矩阵,其中元素按顺时针顺序排列,可以按照螺旋顺序逐步填充矩阵。类似之前的“螺旋矩阵”问题,我们需要依次遍历矩阵的边界,然后按照顺时针方向填充每个位置。
解决方案的关键点:
- 通过定义边界(左、右、上、下)来控制矩阵的填充范围。
- 按顺时针方向(从左到右、从上到下、从右到左、从下到上)依次填充数字。
- 每填充完一圈,缩小边界,直到矩阵填充完毕。
代码实现:
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> matrix(n, vector<int>(n, 0)); // 初始化 n x n 矩阵
int left = 0, right = n - 1, top = 0, bottom = n - 1; // 定义边界
int num = 1; // 要填充的数字
while (left <= right && top <= bottom) {
// 从左到右填充上边界
for (int i = left; i <= right; ++i) {
matrix[top][i] = num++;
}
top++; // 上边界向下收缩
// 从上到下填充右边界
for (int i = top; i <= bottom; ++i) {
matrix[i][right] = num++;
}
right--; // 右边界向左收缩
// 从右到左填充下边界
if (top <= bottom) {
for (int i = right; i >= left; --i) {
matrix[bottom][i] = num++;
}
bottom--; // 下边界向上收缩
}
// 从下到上填充左边界
if (left <= right) {
for (int i = bottom; i >= top; --i) {
matrix[i][left] = num++;
}
left++; // 左边界向右收缩
}
}
return matrix;
}
int main() {
int n = 3; // 矩阵的大小 (n x n)
vector<vector<int>> matrix = generateMatrix(n);
// 输出矩阵
for (const auto& row : matrix) {
for (int elem : row) {
cout << elem << " ";
}
cout << endl;
}
return 0;
}
代码解释:
- 初始化矩阵:使用
vector<vector<int>> matrix(n, vector<int>(n, 0))
初始化一个n x n
的全零矩阵。 - 定义边界:
left
、right
、top
、bottom
分别表示矩阵的四个边界,初始时分别为矩阵的最外层。 - 填充数字:每次按顺时针方向依次填充矩阵:
- 从左到右填充上边界。
- 从上到下填充右边界。
- 从右到左填充下边界。
- 从下到上填充左边界。
每次填充后,缩小相应的边界,直到所有数字填充完毕。
- 输出矩阵:按照二维数组的格式输出矩阵。
输出结果:
对于 n = 3
的情况,输出的螺旋矩阵如下:
1 2 3
8 9 4
7 6 5
复杂度分析:
- 时间复杂度:O(n²),因为我们需要填充
n²
个元素。 - 空间复杂度:O(n²),需要一个
n x n
的矩阵存储结果。
该算法能够生成任意大小的螺旋矩阵。
如何创建一个纯1的矩阵?
vector<vector<int>> matrix(rows, vector<int>(cols, 1));
有点嵌套的感觉,里面再创建一个纯1的数组
奇偶矩阵的边界在何处做限制
原先不知道如何处理,因为奇偶矩阵遍历次数不一样
从左向右和从上到下是共同有的,但是否需要
if (top <= bottom)为什么要有这个限制?
- 避免重复遍历
在填充矩阵的过程中,如果某一边界(如上边界 top 或下边界 bottom)已经被填充完毕并收缩,那么在后续的填充操作中就不需要再次访问这条边界。以下是这两个条件的作用:
if (top <= bottom):这个条件用于确保在填充下边界时,只有当上边界仍然在下边界之上时,才进行填充。这可以防止在 top 已经超过 bottom 的情况下,再尝试填充下边界。
if (left <= right):类似地,这个条件用于确保在填充左边界时,只有当左边界仍然在右边界之左时,才进行填充。这可以防止在 left 已经超过 right 的情况下,再尝试填充左边界。
不一定需要先把num数组做出来,可以只用Num=1,然后在过程中累加
就是我的初始解法会构造数组,但对于这种正序数组,1234567,其实有一个起点就行了。不用特意算一遍存储,节省了存储空间