题目描述
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 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.
思路:显然是脑子里想的很简单,但是实际代码中的边界条件不太容易找准。因此主要分析边界。
如果是4×4的矩阵,顺时针打印第一行时什么时候作为结束的判断标志,顺时针从列开始时,什么时候开始,什么时候结束,都需要考虑清楚。显然本份代码使用的边界是这样的,一共分为4轮完成一圈的遍历,
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
首先是123,然后是4,8,12。然后是16,15,14。最后13,9,5。由于这样的遍历方式,导致行在遍历或者列在遍历时,最后一个元素都无法打印,而是在下一种遍历方式中遍历。比如4是在第4列遍历时才打印,而不是在第一行的时候打印。因此这种遍历方式,需要考虑二种特殊情况,只有一行时以及只有一列时需要单独考虑,否则会漏掉最后一个元素,比如单行只有1234时,遍历只有123而不会出现4,因此单独考虑(列同理)。
这种遍历方法在遍历到最内圈时,是(6),(7),(11),(10)的方式,也就是说,即使6和7在同一行,6是在行遍历时打印,7是作为列的首元素遍历时打印,而不是在6的行遍历时出现。
这样遍历的优势是,遍历比较有规律,在任何一行遍历或者列遍历时,都是有头没尾。因此在边界条件的写法上,也比较有规律,比较容易找到边界比如都是以判断是否到了尾部,到尾部就停止循环,而将最后元素留给下一次循环。
import java.util.ArrayList; public class Solution { ArrayList arr =new ArrayList(); public ArrayList printMatrix(int [][] matrix) { int startRow=0; //起始的行,上边界 int startCow=0; //起始列 左边界 int row = matrix.length-1; //二维数组行的长度 下边界 int col = matrix[0].length-1; //二维数组列的长度 右边界 while(startRow <= row && startCow <= col){ //打印一圈后,二维数组长度减2 宽度减2 //也就是左边界+1,右边界-1,上边界+1,下边界-1 printEdge(matrix,startRow++,startCow++,row--,col--); } return arr; } public void printEdge(int[][] matrix,int startRow,int startCow,int row,int col) { if(startRow == row){ //先判断是否只是一横行(上边界和下边界重合时只有一行) for(int i = startCow;i <= col;i++){ arr.add(matrix[startRow][i]); } } else if(startCow == col){//判断是否只是一列(左边界和右边界重合时只有一列) for(int i=startRow;i<=row;i++){ arr.add(matrix[i][startCow]); } } else { //进入这里说明不止一行一列 int curC = startCow;//用2个变量储存 记录当前位置 标记到哪一列了 int curR = startRow; //标记到哪一行了。 while(curC != col){ //行的遍历 (首个元素到倒数第二个元素打印) arr.add(matrix[startRow][curC]); curC++;//行坐标++ 指针指向最后一个数,但并未添加到arr中。 //指向的最后一个数,作为下一次遍历的首元素 } while(curR!=row){//列的从上至下的遍历(打印首个元素到倒数第二个元素) arr.add(matrix[curR][col]); curR++; //列坐标++,此时到指向列最后一个数,而并未添加到arr中 } while(curC != startCow){ //行的从右向左 arr.add(matrix[row][curC]); curC--; //最后一个元素留出来 } while(curR != startRow){ //列的从下向上 arr.add(matrix[curR][startCow]); curR--;//最后一个元素留出来,其实这个元素在行的从左到右遍历中已经打印 } } } }
也可以只使用一个变量。这是因为每一次行或者列遍历,只有一个角标在变。但是边界判断不如上面的简洁。某位大佬的写法:链接:https://www.nowcoder.com/questionTerminal/9b4c81a02cd34f76be2659fa0d54342a?f=discussion
import java.util.ArrayList; public class Solution { ArrayList<Integer> list = new ArrayList<>(); public ArrayList<Integer> printMatrix(int [][] matrix) { int rows = matrix.length; int columns = matrix[0].length; int start = 0; while(rows > start*2 && columns > start*2){ printMatrix(matrix, rows, columns, start); start++; } return list; } public void printMatrix(int[][] matrix, int rows, int columns, int start) { // 从左到右打印一行 for(int i = start; i < columns - start; i++) list.add(matrix[start][i]); // 从上到下打印一列 for(int j = start + 1; j < rows - start; j++) list.add(matrix[j][columns - start - 1]); // 从右到左打印一行 for(int m=columns-start-2; m>=start && rows-start-1 > start; m--) list.add(matrix[rows - start - 1][m]); // 从下到上打印一列 for(int n=rows-start-2; n>=start+1 && columns-start-1 > start; n--) list.add(matrix[n][start]); } }