59.螺旋矩阵

190 阅读3分钟

题目

给你一个正整数 n ,生成一个包含 1 到 n2n^2  所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例

image.png

输入: 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;
}
  • 时间复杂度 O(n2)O(n^2)
  • 空间复杂度 O(1)O(1) --- 不考虑返回的二维数组的话

总结

  • 本题目的不是传统的算法题,主要考察如何用代码模拟这个画矩阵的过程。

  • 对于循环中边界条件的理解,这里和二分查找一样,都是采用循环不变量,这样统一了循环条件,代码书写起来条理会更加的清晰。