题目
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。例如:如果输入如下矩阵:
1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
则依次打印出数字1、2、3、4、8、12、16、15、14、13、9、5、6、7、11、10。
解题思路
从外圈到内圈顺序的依次打印,我们就可以把矩阵想象成若干个圈,如上图所示,我们可以用一个循环来打印矩阵,每一次打印矩阵中的一个圈。那么循环结束的条件是什么?假设这个矩阵的行数是row,列数是col。打印第一圈的左上角的坐标是(0, 0),第二圈的左上角的坐标是(1, 1),依次类推。我们注意到左上角的坐标中行标和列标总是相同的,于是可以在矩阵中选取左上角为(start,start)的一圈作为我们的分析的目标。
对于一个5*5的矩阵,最后一圈只有一个数字,对应的坐标为(2, 2),即 5 > 2 * 2;
对于一个6*6的矩阵,最后一圈有4个数字,其左上角的坐标仍是(2, 2),即 6 > 2 *2;
故循环继续的条件为col > startX * 2并且row > startY * 2。
同时,分析打印一圈的实现可以分为4步:第一步从左到右打印一行,第二步从上到下打印一列,第三步从右到左打印一行,第四步从下到上打印一列(每一步根据起始坐标和终止坐标用一个循环就能打印出一行或者一列)。
注意:最后一圈可能退化成只有一行、只有一列,甚至只有一个数字,因此打印这样的一圈就不再需要四步,可能只需要三步、两步、一步。
接下来我们分析打印时每一步的前提条件。第一步总是需要的,因为打印一圈至少有一步。如果只有一行,那么就不用第二步了。即第二步的前提条件是终止行号大于起始行号。打印第三步的前提条件是圈内至少有两行两列。即除了要求终止行号大于起始行号外,还需要终止列号大于起始列号。同理打印第四步的前提条件是至少有3行2列,即要求终止行号比起始行号至少大2,同时终止列号大于起始列号。
代码如下:
public class test {
public static void main(String[] args) throws IOException {
int[][] a = new int[4][4];
int k=1;
for(int i=0;i<4;i++) {
for(int j=0;j<4;j++) {
a[i][j]=k;
k++;
}
}
print(a,4,4);
}
public static void print(int[][] a,int row,int col) {
if(a==null||row<=0||col<=0) {
return;
}
int s = 0;
while(col>s*2&&row>s*2) {
printf(a,row,col,s);
s++;
}
}
public static void printf(int[][] a,int row,int col,int s) {
int endx = col-1-s;
int endy = row-1-s;
for(int i=s;i<=endx;i++) {
System.out.print(" "+a[s][i]);
}
if(s<endy) {
for(int i=s+1;i<=endy;i++) {
System.out.print(" "+a[i][endx]);
}
}
if(s<endx&&s<endy) {
for(int i=endx-1;i>=s;i--) {
System.out.print(" "+a[endy][i]);
}
}
if(s<endx&&s<endy-1) {
for(int i=endy-1;i>=s+1;i--) {
System.out.print(" "+a[i][s]);
}
}
}
}