劍指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

相關文章
相關標籤/搜索