劍指offer-4-面試題20:順時針打印矩陣(畫圖使抽象問題形象化)

題目

輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每一個數字。例如:如果輸入如下矩陣:

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

分析

這道題完全沒有涉及複雜的數據結構或者高級的算法,看起來是一個很簡單的問題。但實際上解決這個問題,會在代碼中包含多個循環,並且還需要判斷多個邊界條件。如果在把問題考慮得很清楚之前就開始寫代碼,不可避免會越寫月混亂。因此解決這個問題的關鍵在於先要形成清晰的思路,並把複雜的問題分解成若干個簡單的問題。

當我們遇到一個複雜的問題的時候,可以用圖形來幫助我們思考。由於是以從外圈到內圈的順序依次打印,我們可以把矩陣想象成若干個圈,如圖。我們可以用一個循環來打印矩陣,每一次打印矩陣中的一個圈。
這裏寫圖片描述

接下來分析循環結束的條件。假設這個矩陣的行數是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

void PrintMatrixClockwisely( int **numbers, int columns, int rows )
{
    if( numbers == NULL || columns <=0 || rows <=0 )
        return;
    int start = 0;
    while(columns >start*2 && rows > start*2 )
    {
        PrintMatrixInCircle( numbers, columns, rows, start );
        ++start;
    }
}

接着考慮打印一圈的功能,即如何實現PrintMatrixInCircle。如圖4.3所示,我們可以把打印一圈分爲四步:
第一步從左到右打印一行
第二步從上到下打印 一列
第三步從左到右打印一行
第四步從下到上打印一列
每一步我們根據起始座標和終止座標用一個循環就能打印出一行或者是一列

不過值得注意的是,最後一圈有可能退化成只有一行、只有一列,甚至只有一個數字,因此打印這樣的一圈就不再需要四步。圖 4.4是幾個退化的例子,打印一圈分別只需要三步、兩步甚至只有一步。
這裏寫圖片描述

因此我們要仔細分析打印時每一步的前提條件。第一步總是需要的,因爲打印一圈至少有一步。如果只有一行,那麼就不用第二步了。也就是需要第二步的前提條件是終止行號大於起始行號。需要第三步打印的前提條件是圈內至少有 兩行兩列,也就是說除了要求終止行號大於起始行號之外,還要求終止列號大於起始列號。同理,需要打印第四步的前提條件是至少有三行兩列,因此要求終止行號比起始行號至少大於2,同時終止列號大於起始列號。

void PrintMatrixInCircle( int ** numbers, int columns, int rows, int start )
{
    int endX = columns - 1 - start;
    int endY = rows -1 - start;

    //從左到右打印一行
    for( int i=start; i<=endX; ++i )
    {
        int number = number[start][i];
        printNumber( number );
    }
    //從上到下打印一列
    if( start<endY )
    {
        for( int i=start+1; i<=endY; ++i )
        {
            int number = numbers[i][endX];
            printNUmber(number);
        }
    }

    //從右到左打印一行
    if( start<endX &&  start<endY )
    {
        for( int i=endX-1; i>=start; --i )
        {
            int number = numbers[endY][i];
            printNUmber(number);
        }
    }
    //從下到上打印一列
    if( start<endX && start<endY-1 )
    {
        for(int i=endY-1; i>=start+1; --i )
        {
            int number = numberss[i][start];
            printNumber( number );
        }
    }
}

測試用例&代碼

數組有多行多列、數組只有一行、數組只有一列、數組中只有一行一列

本題考點

本題主要考察應聘者的思維能力。從外到內順時針打印矩陣這個過程非常複雜,應聘者如何能很快地找出其規律並寫出完整的代碼,是解決這道題的關鍵。當問題比較抽象不易理解時,可以試着畫幾個圖形幫助理解,這樣往往能更快地找到思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章