题目描述:
输入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)时的打印等等,都可以用到类似的办法来解决。