剑指Offer(Java版):顺时针打印矩阵

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

1,2,3,4class

5,6,7,8test

9,10,11,12循环

13,14,15,16im

则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.static

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

接下来分析循环结束的条件。假设这个矩阵的行数是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.while

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

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

所以咱们要仔细分析打印时的每一步的前提条件。第一步老是须要的,因 为打印一圈至少须要一步。若是只有一行,那么就不用第二步了。也就是须要第二步的前提条件是终止号大于起止号。须要第三步打印的前提条件是圈内至少有两行 两列,也就是说除了要求终止行号大于起始行号以外,还要求终止列号大于起始列号。同理,须要打印第四步的前提条件是至少有三行两列,所以要求终止行号比其 实行号至少大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 <endY){  
            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 <endY && start <endY -1){  
            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的时候,咱们只须要第一步就把全部的数字都打印完了,其他的步骤都是多余的。所以咱们须要考虑第2、3、四步打印的条件。根据前面咱们分析,不难发现打印第二步的条件是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

相关文章
相关标签/搜索