数组和矩阵问题:转圈打印矩阵
【题目】
给定一个整型矩阵 matrix, 请按照转圈的方式打印它。
例如:
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
【要求】
额外空间复杂度为 O(1)。
【难度】
一星
【解答】
本题在算法上没有什么难度,关键在于设计一种逻辑容易理解、代码易于实现的转圈遍历方式。这里介绍这样一种矩阵处理方式,该方式不仅可用于此题,还适合很多其他的面试题,就是矩阵分圈处理。在矩阵中用左上角的坐标 (tR, tC) 和右下角的坐标 (dR, dC) 就可以表示一个子矩阵,比如,题目中的矩阵,当 (tR, tC) = (0, 0)、(dR, dC) = (3,3) 时,表示子矩阵就是整个矩阵,那么这个子矩阵最外层的部分如下:
1 2 3 4
5 8
9 12
13 14 15 16
如果能把这个矩阵的外层转圈打印出来,那么在(tR, tC) = (0,0)、(dR, dC) = (3,3) 时,打印的结果为:1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5。接下来令 tR 和 tC 加 1,即 (tR, tC) = (1,1), 令 dR 和 dC 减 1, 即 (dR, dC) = (2,2), 此时表示的子矩阵如下:
6 7
10 11
再把这个子矩阵转圈打印出来,结果为:6, 7, 11, 10。再令 tR 和 tC 加 1,即(tR, tC) = (2,2), 令 dR 和 dC 减 1, 即 (dR, dC) = (1,1)。如果发现左上角坐标跑到了右下角坐标的右方或者下方,整个过程就停止了。已经打印的所有结果连起来就是我们要求的打印结果。具体请参看如下代码中的 spiralOrderPrint 方法, 其中 printEdge 方法是转圈打印一个子矩阵的外层。
1 public class Main { 2 3 public static void main(String[] args) { 4 int[][] matrix = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; 5 //1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10 6 new Main().spiralOrderPrint(matrix); 7 } 8 9 //打印矩阵 10 public void spiralOrderPrint(int[][] matrix) { 11 int tR = 0; 12 int tC = 0; 13 int dR = matrix.length - 1; 14 int dC = matrix[0].length - 1; 15 while(tR <= dR && tC <= dC){ 16 printEdge(matrix, tR++, tC++, dR--, dC--); 17 } 18 } 19 20 //打印子矩阵 21 public void printEdge(int[][] m, int tR, int tC, int dR, int dC) { 22 if(tR == dR){ //当子矩阵只有一行时 23 for(int i = tC; i <= dC; i++){ 24 System.out.print(m[tR][i] + " "); 25 } 26 }else if(tC == dC){ //当子矩阵只有一列时 27 for(int i = tR; i <= dR; i++){ 28 System.out.print(m[i][tC] + " "); 29 } 30 }else{ //一般情况 31 int curC = tC; 32 int curR = tR; 33 while(curC != dC){ //向右方向 34 System.out.print(m[tR][curC++] + " "); 35 } 36 while(curR != dR){ //向下方向 37 System.out.print(m[curR++][dC] + " "); 38 } 39 while(curC != tC){ //向左方向 40 System.out.print(m[dR][curC--] + " "); 41 } 42 while(curR != tR){ //向上方向 43 System.out.print(m[curR--][tC] + " "); 44 } 45 } 46 } 47 48 }