逐行打印螺旋矩阵(O(1)空间 C++附解析)

最近听面试的同学考到了这道题,事先保存后打印的方法应该都会,或者搜一下有一大堆的,保存方向进行循环即可
但逐行打印的却较少,挺有趣也挺绕的
首先明确:设边长为n;
则最外圈有4 * (n - 1)个数;此外圈有4*(n - 3)个数,以此类推
因此可以先构造一个数组,保存到该圈之前,已有多少数字
此外,对于如下O(i, j)所在位置,如何判断其属于第几个圈呢?

* * * * * *
* x * * * *
* * * * o *
* * * * * *
* * * * * *

直接看其距离边界的最小值:
距离最左端距离为4, 距离最顶端距离为2,最右端距离为1,最下端距离为2
因此说明其属于第二个圈,那么该圈的初始值为21(最外圈用了20个数)
此后判断其存在的数字:由于这个level=1=n-j,由此判断从第二个圈的起始位置x开始的那一行是填满的,接下来的一列填了j-1-level个数字(level表示所属的圈,这里是否-1或level从0开始还是从1开始都可以,但会影响这个算式)
同理若level=i-1,则说明这个数字在起始位置开始的那一行
若n-i=level,在从右往左的那一行
若j-1=level,在起始位置的那一列
由此即实现O(1)空间复杂度,O(n)时间复杂度的代码:

#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
#define min(a, b) ((a) < (b)? (a) : (b))
void printMatrix(int n)
{
	// 预先存下已用的数字数 (由于要求O(1)大小空间,因此这个数组后续未曾使用)
	int *amount = new int[n / 2 + 1];
	amount[0] = 0;
	for (int i = 1; i <= n / 2; ++i)
		amount[i] = amount[i - 1] + 4 * (n - 2 * i + 1);

	for (int i = 1; i <= n; ++i)
	{
		for (int j = 1; j <= n; ++j)
		{
		 	// 获得当前的点所在的圈数
			int level = min(min(i - 1, j - 1), min(n - i, n - j));
			// 该圈起始数字
			// int initial = amount[level] + 1;
			int initial = 4 * level * n + 1;
			if (i - 1 == level) cout << setw(5) << initial + j - 1 - level;
			else if (n - j == level) cout << setw(5) << initial + n - 2 * level - 1 + i - 1 - level;
			else if (n - i == level) cout << setw(5) << initial + 2 * n - 4 * level - 2 + n - level - j;
			else cout << setw(5) << initial + 3 * n - 6 * level - 3 + n - level - i;
		}
		cout << endl;
	}
}

int main()
{
	for (int n; cin >> n;)
		printMatrix(n);
	return 0;
}

输出:

5
    1    2    3    4    5
   16   17   18   19    6
   15   24   25   20    7
   14   23   22   21    8
   13   12   11   10    9
7
    1    2    3    4    5    6    7
   24   25   26   27   28   29    8
   23   40   41   42   43   30    9
   22   39   48   49   44   31   10
   21   38   47   46   45   32   11
   20   37   36   35   34   33   12
   19   18   17   16   15   14   13
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值