在O(1)的空间复杂度内,打印螺旋数组

本文探讨如何在不使用额外空间的情况下,以螺旋顺序打印二维数组。这种算法常见于编程面试中,挑战在于如何巧妙地利用原数组的索引来实现螺旋遍历。
摘要由CSDN通过智能技术生成
题目描述:
输入n,输出格式为一个(2n-1)*(2n-1)的二维数组,从内到外,每一层元素为1,2,3...n,在O(1)时间复杂度内打印出这个螺旋数组。

要求:
空间复杂度为O(1)

case:
输入 
3
输出
3 3 3 3 3
3 2 2 2 3
3 2 1 2 3
3 2 2 2 3
3 3 3 3 3

分析:
这道题目和leetcode上的题目(lee上有两道螺旋数组的题目)有所不同的是空间复杂度要求为O(1)。所以不能够先开辟一个二维数组来存储每一层的这些值。

那么考虑一下,如何找到二维数组每个元素a[i][j]与n的关系?实际上,这个二维数组有一个特点,就是每一层(每一圈元素是一层)的元素相同,所以我们只要确定a[i][j]属于哪一层(我们叫做level,表示第level圈元素),就知道a[i][j]元素的值了。

那么对于a[i][j]而言,如何根据i和j来确定a[i][j]的层次呢?我们观察一下,二维数组的各个元素下标(i,j)。

(0, 0) (0, 1) (0, 2) (0, 3) (0, 4)
(1, 0) (1, 1) (1, 2) (1, 3) (1, 4)
(2, 0) (2, 1) (2, 2) (2, 3) (2, 4)
(3, 0) (3, 1) (3, 2) (3, 3) (3, 4)
(4, 0) (4, 1) (4, 2) (4, 3) (4, 4)

仔细观察发现,第0层(从外向内算的第一圈元素,共有上、下、左、右四条边)中:
上边的元素行号都为i = 0;
右边的元素列号都为j = 4,(5 - 1 - 4 = 0);
下边的元素行号为i = 4(5 - 1 - 4 = 0);
左边的元素列号为j = 0。
所以将矩阵分为右上、左下两部分,可以看出在右上的元素中,层次level由i和2n-1-1-j(2n-1在这里是二维矩阵的边长)中较小的值确定,在左下的元素中,level由2n-1-1-i和j中较小的值确定。

所以,对于二维矩阵中任一位置a[i][j], a[i][j]所处的层的计算公式为:
level = min(i, n - 1 - j) (i<=j时);
level = min(j, n - 1 - i) (i>j时)。
得到这一特点以后,算法的实现变得非常简单。

#include <iostream>
#include <cmath>
using namespace std;

void printSpiralMatrix(int n) {
	int w = 2*n-1; // 矩阵的边长2n-1,level从1->n
	for (int i = 0; i < w; ++i) {
		for (int j = 0; j < w ; ++j) {
			int level;
			if (i <= j) {
				level = min(i, w-j-1);
			}	
			else {
				level = min(j, w-i-1);
			}
			cout << n-level << " ";
		}
		cout << endl;
	} 
	
}

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


此外:此题可以有非常多的变种,例如最基础的就是leetcode上的顺时针/逆时针从1到n打印二维数组。还有第一圈是顺时针打印,第二圈是逆时针打印,交替进行打印二维数组。还有像剑指offer中的m*n的二维矩阵(m != n)时的打印等等,都可以用到类似的办法来解决。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值