思路:观察发现,在填充过程中,总能找到一个时刻,使得二维矩阵的“最外层”均填充完毕,同时“内层?”均未被填充过。于是可以以“圈”为单位考虑整个填充过程,即每次循环填充一圈。而每一圈由四个填充过程组成,分别是最上层,最右层,最下层,最左层。当每一层填充完毕后,便向内层收缩一圈,例如最上层是向下移动一行。需要注意的是每层填充都会把下一次填充时要填的第一个数填掉,所以除了整个填充过程中的第一次填充,其余每层都要跳过上一层的最后一个数,从本层的第二个数开始填充
代码如下:
import java.io.*;
import java.util.*;
public class Main {
//找n的方法,从算数平方根向下查询,找到的第一个
public static int Factor(int a){
int factor=0;
for(int i=(int)Math.sqrt(a);i>=1;i--){
if(a%i==0) {
factor=i;
break;
}
}
return factor;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
StreamTokenizer in = new StreamTokenizer(br);
in.nextToken();
int N=(int)in.nval;
int n=Factor(N),m=N/n;
int[] data=new int[N];
for(int i=0;i<N;i++){
in.nextToken();
data[i]=(int)in.nval;
}
//sort后逆序填入螺旋矩阵
Arrays.sort(data);
int[][] result=new int[m][n];
//用来记录有没有填完的计数器
int count=0;
/*
floor:每个循环中填充的最下面一行
ceil:每个循环中填充的最上面一行
*/
int floorRow=m-1,ceilRow=0;
/*
right:每个循环中填充的最右边一列
left:每个循环中填充的最左边一列
*/
int right=n-1,left=0;
/*
每次填一圈 由于不知道具体哪个小循环过后会填完,所以每个小循环后都判断一下count,如果填完break
*/
while(count<N){
//取当前填充的最上边一行,从左往右填充
for(int i=left;i<=right;i++){
result[ceilRow][i]=data[N-1-count];
count++;
}
if(count==N) break;
//由于上一次填充把最右边一列的第一个数要填的数填掉了,所以ceil下降一行
ceilRow++;
//取当前填充的最右边一列,从上往下填充
for(int j=ceilRow;j<=floorRow;j++){
result[j][right]=data[N-1-count];
count++;
}
if(count==N) break;
//由于上一次填充把最下边一行的第一个要填的数填掉了,所以right左移一列
right--;
//取当前填充的最下边一行,从右往左填充
for(int i=right;i>=left;i--){
result[floorRow][i]=data[N-1-count];
count++;
}
if(count==N) break;
//由于上一次填充把最左边一列的第一个要填的数填掉了,所以floor上移一列
floorRow--;
for(int j=floorRow;j>=ceilRow;j--){
result[j][left]=data[N-1-count];
count++;
}
if(count==N) break;
//下一圈时,由于上一圈的最后一次填充把当前填充的最上边一列的第一个要填的数填掉了,所以left右移一列
left++;
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(j==n-1){
out.print(result[i][j]);
}
else{
out.print(result[i][j]+" ");
}
}
out.println();
}
out.flush();
}
}
这道题是压线AC的,提交了好几发,终于把测试点6,7都过了?
|