创新工场会有一个统一的笔试,笔试过了之后会有面试,这个面试过了之后,可以参加后面的双选会,双选会的单位一般是从创新工场孵化成功的企业。
今天参的是第一场面试。开始聊项目,后面问了一个螺旋矩阵的问题,螺旋矩阵的问题见过,但是吃亏就吃在没有把自己的思路讲清除,这里再梳理一下。
有一个n*n的矩阵如下排列,将矩阵打印出来。
eg:
解法一:首先分配一个n*n的整型数组,根据螺旋的递增顺序,将对应的数组中元素赋值。时间复杂度O(n^2),空间复杂度O(n^2)。面试官可能希望我给出这个思路,但是由于已有知识,一开始就没考虑到这种做法。下面有一种时间复杂度相同,空间复杂度O(1)的方法。
解法二:先看一个“从中心开始递增的螺旋队列问题”,
有一个n*n的矩阵如下排列,将矩阵打印出来。
eg:
假如能打印已知矩阵的一个元素为x,那么只需要将该元素用n^2+1-x替换掉就可以得到从外层开始递增的螺旋队列。如何得到x?
分四种情况讨论:(i,j)表示相对于中心(0,0)的横坐标,纵坐标
if(i==-layer) //在上边,
v=v-layer-j; //随横坐标递减
else if(i==layer) //在下边
v=v-5*layer+j; //随横坐标递增
else if(j==layer) //在右边
v=v-3*layer-i;
else //在左边
v=v-3*layer+i;
显然这两个问题的差别不仅在此,原问题中n可以是奇偶数,而归约的问题中n只能是奇数。那么当n是偶数的时候如何处理呢。可以观察下面矩阵
将该矩阵分成三部分
1*4
3*3 3*1
左下角3*3的矩阵可以通过类似上面的分析得到,但由于上面1*n和左面(n-1)*1的元素数,因此需要在原来的基础上加上2*n-1。即(n-1)^2-x+2n。x的获取方法与上面类似,当还需要一个180的旋转。
至此问题分析结束,下面给出完整代码:
#include <stdio.h>
#define max(a,b) (a)>(b)?(a):(b)
#define abs(a) (a)>0?(a):(-(a))
int getX(int i,int j)
{
int layer=max(abs(i),abs(j));//求出层数
int v=layer*2 +1;
v=v*v;
if(i==-layer)
v=v-layer-j;
else if(i==layer)
v=v-5*layer+j;
else if(j==layer)
v=v-3*layer-i;
else
v=v-3*layer+i;
return v;
}
void printEvenM(int n)
{
int sum=(n-1)*(n-1)+2*n;
int layerN=n/2-1;
for(int i=0;i<n;i++)
printf("%d ",i+1);
printf("\n");
for(int i=-layerN;i<=layerN;i++)
{
for(int j=-layerN;j<=layerN;j++)
{
printf("%d ",sum-getX(-i,-j)); //-i,-j表示旋转180度
}
printf("%d\n",n+i+layerN+1);
}
}
void printOddM(int n)
{
int sum=n*n+1;
int layerN=n/2;
for(int i=-layerN;i<=layerN;i++)
{
for(int j=-layerN;j<=layerN;j++)
{
printf("%d ",sum-getX(i,j));
}
printf("\n");
}
}
void printM(int n)
{
if(n%2)
printOddM(n);
else
printEvenM(n);
}
int main()
{
printM(6);
return 0;
}