题目
给你一个正整数 n ,生成一个包含 1 到 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
示例
输入: n = 3
输出: [[1,2,3],[8,9,4],[7,6,5]]
思路
根据题目想象如何模拟顺时针画矩阵的过程:
- 填充上行从左到右
- 填充右列从上到下
- 填充下行从右向左
- 填充左列从下到上
由此可以得出每一圈都是由着四步组成,可以通过4个平行的for循环去实现这四步。
关键点
-
注意每一次for循环中循环变量的判处条件(即边界条件),我们应该统一4次for循环的边界条件,这里按照左闭右开原则来进行for循环的判断。
-
注意每一次遍历一条边的时候的起始位置的变换。
-
注意当n为奇数的时候,会有一个中心位置的元素需要额外赋值。
c++代码实现
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
// 返回类型为一个二维数组
vector<vector<int>> generateMatrix(int n) {
// vector<int> res(len,
// element);其中第一个参数为指定数组长度,第二个元素指定每个元素的初值
vector<vector<int>> res(n, vector<int>(n, 0));
//使用vector定义一个二维数组
int startx = 0, starty = 0;
//定义每圈循环的起始位置(startx,starty)
int loop = n / 2;
//生成一个按顺时针顺序螺旋排列的n*n的的正方形矩阵,需要循环的圈数
//,列入n=2,则loop=1,只需要循环一圈就可以得到该矩阵
int mid = n / 2;
//当n为奇数时矩阵的中心位置
int count = 1;
//用来给矩阵中每一个元素赋值
int offset = 1;
//需要控制不同圈中每一条边遍历的长度,即每次循环有边界都要收缩一位(n
//- offset)
int i, j;
while (loop--) {
//下面的4个for循环就是模拟螺旋排列一圈
//从起始位置(startx,starty)开始,模拟上行自左向右,并且遵循循环不变量(边界按照左闭右开)
for (j = starty; j < n - offset;
j++) {
//遍历元素即第一行第一个元素到倒数第二个(右开)
res[startx][j] = count++;
}
//从位置(startx,n-offset-1)开始,模拟右列从自上向下,并且遵循循环不变量(边界按照左闭右开)
for (i = startx; i < n - offset; i++) {
res[i][j] = count++;
}
//从位置(n-offset-1,j)开始,模拟下行从自右向左,并且遵循循环不变量(边界按照左闭右开)
for (; j > starty; j--) {
//这是j = i = n - offset -1
res[i][j] = count++;
}
//从位置(n-offset-1,starty)开始,模拟左列从自下向上,并且遵循循环不变量(边界按照左闭右开)
for (; i > startx; i--) {
res[i][j] = count++;
}
//从第二圈开始,起始位置发生改变,各自加一,例如第一圈为(0,0),第二圈为(1,1)
startx++;
starty++;
// offset 控制每一圈里每一条边遍历的长度
offset += 1;
}
//如果n为奇数的话,中间元素需要单独处理(单独赋值)
if (n % 2 == 1)
res[mid][mid] = count;
return res;
}
};
int main() {
//测试一下
Solution s1;
vector<vector<int>> res = s1.generateMatrix(3);
//使用迭代器的方式访问res(二维数组)
vector<int> res_temp;
for (auto it = res.begin(); it != res.end(); it++) {
res_temp = *it;
//使用中间变量
for (auto it = res_temp.begin(); it !=res_temp.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
return 0;
}
- 时间复杂度
- 空间复杂度 --- 不考虑返回的二维数组的话
总结
-
本题目的不是传统的算法题,主要考察如何用代码模拟这个画矩阵的过程。
-
对于循环中边界条件的理解,这里和二分查找一样,都是采用循环不变量,这样统一了循环条件,代码书写起来条理会更加的清晰。