接着上篇:
[矩阵]螺旋矩阵问题(上):http://blog.youkuaiyun.com/beyongwang/article/details/52089951
网上看到有一种比较通用易懂的算法(参考:http://www.cnblogs.com/eshizhan/archive/2010/06/01/1749013.html),结合这个思路详细的分析一下螺旋矩阵问题,以及如何灵活的改变螺旋的方向以及排列顺序。
首先观察一下有内到外的顺时针的5*5螺旋矩阵:
如果把该矩阵放入坐标系中,按照二维数组的行列增长方向:X轴右方向增大,Y轴下方向增大。效果如下(每个元素/格子代表一个点,而不是每根线,所以下图是坐标是0到4,X和Y轴各有五个点):
如果以该矩阵的中心点为中心,将矩阵分成四部分,观察各部分X,Y的变化,可以发现上面部分是X增加,下面部分是X减少,左面部分是Y减少,右面部分是Y增加:
继续观察两条分割线,可以发现他们实际上是两条直线方程X = 4 - Y和X = Y,而四部分分别满足不同的条件(先不考虑点正好在直线上的情况,稍后会说到),如下:
- 一部分:X > Y 并且X < 4 - Y。
- 二部分:X > Y 并且X > 4 - Y。
- 三部分:X < Y 并且X > 4 - Y。
- 四部分:X < Y 并且X < 4 - Y。
继续分析点落在直线方程的情况,看下图,以3,5,7,9四个点为例,对于3点,它的下一步要往左(--X)所以它属于区域三,类似的推断方法,5属于区域四,7属于区域一,9属于区域一,所以考虑点落到线上的情况则四个区域满足的条件为:
- 一部分:X >= Y 并且X <= 4 - Y。
- 二部分:X > Y 并且X > 4 - Y。
- 三部分:X <= Y 并且X > 4 - Y。
- 四部分:X < Y 并且X <= 4 - Y。
vector<vector<int>> generateSpiralMatrixI(int n) {
vector<vector<int>> retVec(n, vector<int>(n, 0));
if (0 == n)//边界条件判断
{
return retVec;
}
int x = n / 2;
int y = n / 2;
for(size_t index = 1; index <= n * n; ++index)//外层循环,负责控制要填充的元素内容
{
if (x >= y && x <= n - 1 - y)//元素落入上图区域一中
{
retVec[y][x] = index;//元素入座
++x;//x增加,即向右移动
}
else if(x > y && x > n - 1 - y)//元素落入上图区域二中
{
retVec[y][x] = index;
++y;//y增加,即向下移动
}
else if (x <= y && x > n - 1 - y)//元素落入上图区域三中
{
retVec[y][x] = index;
--x;//x减少,即向左移动
}
else if (x < y && x <= n - 1 - y)//元素落入上图区域四中
{
retVec[y][x] = index;
--y;//y减少,即向上移动
}
}
return retVec;
}
运行结果如下,注意奇数行列数和偶数行数的矩阵由于起始点不一样(偶数行数中心点其实不在中心),所以前几个元素方向不太一样,但是整体的方向是一致的:
vector<vector<int>> generateSpiralMatrixI(int n) {
vector<vector<int>> retVec(n, vector<int>(n, 0));
if (0 == n)
{
return retVec;
}
int x = n / 2;
int y = n / 2;
for(size_t index = n * n; index >= 1; --index)
{
...//Same as before:D
}
return retVec;
}