java输入一个矩阵顺时针打印_剑指Offer(Java版):顺时针打印矩阵

题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。例如:如果输入如下矩阵:

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.

当遇到一个复杂的问题的时候,我们可以用图形来帮助我们来思考。由于是从外圈到内圈的顺序依次打印,我们可以把矩阵想象成若干个圈,如图所示。我们可疑用一个循环来打印矩阵,每一次打印矩阵中的一个圈。

e1b4fefffa45e4d101abb85b13c7d88d.png

接下来分析循环结束的条件。假设这个矩阵的行数是rows,列数是 columns。打印第一个圈是左上角元素的坐标是(0,0),第二圈的左上角的坐标是(1,1),以此类推。我们注意到,左上角的坐标中行标和列标总是 相同的,于是可疑在矩阵中选取左上角为(start,start)的一圈为我们分析的目标。

对一个5*5的矩阵而言,最后一圈只有一个数字,对应的坐标为 (2,2)。我们发现5>2*2.对于一个6*6的矩阵而言,最后一圈有4个数字,其左上角的坐标仍然为(2,2)。我们发现6>2*2依然 成立。于是我们可以得出继续循环的条件是columns>startX*2并且rows>startY*2.

接着我们考虑如何打印一圈的功能,即如何实现 PrintMatrixInCircle。如图所示,我们可以把打印一圈分为四步:第一步从做到右打印一行,第二步从上到下打印一行,第三步从右到左打印 一行,第四步从下到上打印一列。每一步我们根据起始坐标用一个循环就能打印出一行或者一列。

不过值得注意的是,最后一圈有可能退化成只有一行、只有一列,甚至只有一个数字,因此打印这样的一圈就不再需要四步。图是几个退化的例子,打印一圈分别只需要三步、两步甚至只有一步。

46c2ceea79db346b3dced94d5aa49762.png

因此我们要仔细分析打印时的每一步的前提条件。第一步总是需要的,因 为打印一圈至少需要一步。如果只有一行,那么就不用第二步了。也就是需要第二步的前提条件是终止号大于起止号。需要第三步打印的前提条件是圈内至少有两行 两列,也就是说除了要求终止行号大于起始行号之外,还要求终止列号大于起始列号。同理,需要打印第四步的前提条件是至少有三行两列,因此要求终止行号比其 实行号至少大2,同时终止列号大于起始列号。

package cglib;

public class DeleteNode {

public void printMatrixInCircle(int[][] array){

if(array == null)

return;

int start = 0; //3*4

System.out.println("array[0].length="+array[0].length);

System.out.println("array.length="+array.length);

while(array[0].length > start*2 && array.length >start*2){

printOneCircle(array,start);

start++;

}

}

//1,2,3,4

//5,6,7,8

//9,10,11,12

private void printOneCircle(int[][] array,int start){

int columns = array[0].length; //列数

int rows = array.length;  //行数

int endX = columns - 1 - start;  //3

int endY = rows - 1 - start; //2

//从左到右打印一行

for(int i = start;i <= endX ;i++){

int number = array[start][i];  //1,2,3,4

System.out.print(number+",");

}

//从上到下打印一列

if(start

for(int i = start +1;i<=endY;i++){ //8,12

int number = array[i][endX];  //列固定

System.out.print(number+",");

}

}

//从右到左打印一行

if(start < endX && start < endY){ //11,10,9

for(int i = endX -1;i>=start;i--){

int number = array[endY][i];

System.out.print(number+",");

}

}

//从下到上打印一列

if(start

for(int i =endY -1;i>=start+1;i--){

int number = array[i][start];

System.out.print(number+",");

}

}

}

public static void main(String[]args){

int[][] arr={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

DeleteNode test = new DeleteNode();

test.printMatrixInCircle(arr);

}

输出

array[0].length=4

array.length=3

1,2,3,4,8,12,11,10,9,5,6,7,

或者:

第一步打印一行时,所有的数字的行号是固定的(startY),不同数字的列号不同。我们需要传入一个起始列号(startX)和终止列号(endX)。第二步打印一列时,所有的数字的列号是固定的,不同的数字的行号不同。我们需要传入一个起始行号(startY + 1)和一个终止行号(endY)。第三步和第四步和前面两步类似,读者可以自己分析。

接下来我们需要考虑特殊情况。并不是所有数字圈都需要四步来打印。比如当一圈退化成一行的时候,也就是startY等于endY的时候,我们只需要第一步就把所有的数字都打印完了,其余的步骤都是多余的。因此我们需要考虑第二、三、四步打印的条件。根据前面我们分析,不难发现打印第二步的条件是startY < endY。对于第三步而言,如果startX等于endX,也就是这一圈中只有一列数字,那么所有的数字都在第二步打印完了;如果startY等于endY,也就是这一圈中只有一行数字,那么所有的数字都在第一步打印完了。因此需要打印第三步的条件是startX < endX && startX < endY。第四步最复杂,首先startX要小于endX,不然所有的数字都在一列,在第二步中就都打印完了。另外,这个圈中至少要有三行数字。如果只有一行数字,所有数字在第一步中打印完了;如果只有两行数字,所有数字在第一步和第三步也都打印完了。因此打印第四步需要的条件是startY < endY – 1。

package cglib;

public class DeleteNode {

public void printCircle(int[][] matrix, int startX, int startY, int endX, int endY) {

// 最后只剩一列

if (startY == endY) {

for (int i = startX; i <= endX; i++ ) {

System.out.println("最后只剩一列 :"+matrix[i][endY]);

}

return;

}

// 最后只剩一行

if (startX == endX) {

for (int i = startY; i <= endY; i++ ) {

System.out.println("最后只剩一行:"+matrix[startX][i]);

}

return;

}

for (int i = startY; i < endY; i++ ) {  //从左到右,行数固定

System.out.println("从左到右:"+matrix[startX][i]);

}

for (int i = startX; i < endX; i++ ) {  //从上到下,列数固定

System.out.println("从上到下:"+matrix[i][endY]);

}

for (int i = endY; i > startY; i-- ) {  //从右到左,行数固定

System.out.println("从右到左:"+matrix[endX][i]);

}

for (int i = endX; i > startX; i-- ) { // 从下到上,列数固定

System.out.println("从下到上:"+matrix[i][startY]);

}

}

public void printMatrix(int[][] matrix) {

if (matrix == null) {

return;

}

int startX = 0;

int startY = 0;

int endY = matrix[0].length - 1;  //列

int endX = matrix.length - 1;  //行

while ((startX <= endX) && (startY <= endY)) {

printCircle(matrix, startX, startY, endX, endY);

startX++;

startY++;

endX--;

endY--;

}

}

public static void main(String[]args){

int[][] arr={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

DeleteNode test = new DeleteNode();

test.printMatrix(arr);

}

}

输出:

从左到右:1

从左到右:2

从左到右:3

从上到下:4

从上到下:8

从右到左:12

从右到左:11

从右到左:10

从下到上:9

从下到上:5

最后只剩一行:6

最后只剩一行:7

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值