題目:輸入乙個矩陣,按照從外向裡以順時針的順序依次列印出每乙個數字。
例如:如果輸入如下矩陣:
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。
分析:第一次看到這個題目的時候,覺得這個題目很簡單,完全不需要用到資料結構或者演算法的知識,因此沒有興趣做這道題。後來聽到包括autodesk、emc在內的多家公司在面試或者筆試裡採用過這道題,於是想這麼多家公司用它來檢驗乙個程式設計師的程式設計功底總是有原因的,於是決定自己寫一遍試一下。真正寫一遍才發現,要完整寫出這道題的**,還真不是件容易的事情。
解決這道題的難度在於**中會包含很多個迴圈,而且還有多個邊界條件需要判斷。如果在把問題考慮得很清楚之前就開始寫**,不可避免地會越寫越混亂。因此解決這個問題的關鍵,在於先要形成清晰的思路,並把複雜的問題分解成若干個簡單的問題。下面分享我分析這個問題的過程。
通常當我們遇到乙個複雜的問題的時候,我們可以用圖形幫助我們思考。由於我們是以從外圈到內圈的順序依次列印,我們在矩陣中標註一圈作為我們分析的目標。在下圖中,我們設矩陣的寬度為columns,而其高度為rows。我們我們選取左上角座標為(startx, starty),右下角座標為(endx, endy)的乙個圈來分析。
由於endx和endy可以根據startx、starty以及columns、rows來求得,因此此時我們只需要引入startx和starty兩個變數。我們可以想象有乙個迴圈,在每一次迴圈裡我們從(startx, starty)出發按照順時針列印數字。
接著我們分析這個迴圈結束的條件。對乙個5×5的矩陣而言,最後一圈只有乙個數字,對應的座標為(2, 2)。我們發現5 > 2 * 2。對乙個6×6的矩陣而言,最後一圈有四個數字,對應的座標仍然為(2, 2)。我們發現6 > 2 * 2依然成立。於是我們可以得出,讓迴圈繼續的條件是columns > startx * 2 && rows > starty * 2。有了這些分析,我們就可以寫出如下的**:
void printmatrixclockwisely(int** numbers, int columns,int rows)
}
接下來我們分析如何在printmatrixincircle中按照順時針的順序列印一圈的數字。如同在圖中標註的那樣,我們可以分四步來列印:第一步是從左到右列印一行(上圖中黃色區域),第二步是從上到下列印一列(上圖中綠色區域),第三步從右到左列印一行(上圖中藍色區域),最後一步是從下到上列印一列(上圖中紫色區域)。也就是我們把列印一圈數字這個問題,分解成四個子問題。我們可以為每個子問題定義乙個函式。四個步驟對應的函式名稱我們分別定義為:printarowincreasingly,printacolumnincreasingly,printarowdecreasingly和printacolumndecreasingly。
現在我們暫時不考慮如何去實現這四個函式,而是先考慮我們需要分別給這些函式傳入哪些引數。第一步列印一行時,所有的數字的行號是固定的(starty),不同數字的列號不同。我們需要傳入乙個起始列號(startx)和終止列號(endx)。第二步列印一列時,所有的數字的列號是固定的,不同的數字的行號不同。我們需要傳入乙個起始行號(starty + 1)和乙個終止行號(endy)。第三步和第四步和前面兩步類似,讀者可以自己分析。
接下來我們需要考慮特殊情況。並不是所有數字圈都需要四步來列印。比如當一圈退化成一行的時候,也就是starty等於endy的時候,我們只需要第一步就把所有的數字都列印完了,其餘的步驟都是多餘的。因此我們需要考慮第
二、三、四步列印的條件。根據前面我們分析,不難發現列印第二步的條件是starty < endy。對於第三步而言,如果startx等於endx,也就是這一圈中只有一列數字,那麼所有的數字都在第二步列印完了;如果starty等於endy,也就是這一圈中只有一行數字,那麼所有的數字都在第一步列印完了。因此需要列印第三步的條件是startx < endx && startx < endy。第四步最複雜,首先startx要小於endx,不然所有的數字都在一列,在第二步中就都列印完了。另外,這個圈中至少要有三行數字。如果只有一行數字,所有數字在第一步中列印完了;如果只有兩行數字,所有數字在第一步和第三步也都列印完了。因此列印第四步需要的條件是starty < endy – 1。
有了前面的分析,我們就能寫出printmatrixincircle的完整**如下:
void printmatrixincircle(int** numbers, int columns,int rows,
int startx,int starty)
接下來我們考慮如何列印一行或者一列。這對我們來說不是一件很難的事情。以函式printarowincreasingly為例,我們只需要乙個迴圈,把行號為starty,列號從startx到endx的所有數字依次從陣列中取出來並逐個列印就行了,對應的**是:
void printarowincreasingly(int** numbers, int columns,int rows,
int y,int firstx,int lastx)
}
剩下的三個函式與此類似,**依次如下:
void printacolumnincreasingly(int** numbers, int columns,int rows,
int x,int firsty,int lasty)
}void printarowdecreasingly(int** numbers, int columns,int rows,
int y,int firstx,int lastx)
}void printacolumndecreasingly(int** numbers, int columns,int rows,
int x,int firsty,int lasty)
}
完整**
#include#includeusing namespace std;
void printmatrixincircle(int numbers[100], int rows, int columns, int start)
//從上往下列印
if (start= start; --i)
} //從下往上列印
if (startstart; --i) }}
void printmatrixclockwisely(int numbers[100], int rows, int columns)
}int main()
劍指offer 順時針列印矩陣
題目描述 輸入乙個矩陣,按照從外向裡以順時針的順序依次列印出每乙個數字,例如,如果輸入如下矩陣 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.思路 遞迴列印,處理好邊界就ok...
劍指offer 順時針列印矩陣
題目描述 給定乙個矩陣按照順時針順序從外到內的列印這個矩陣 解題思路 設定乙個全域性的方向向量dir其中的順序是向右,向下,向左,向上 每次給行加上乙個方向向量,當出現越界或者已經列印過的時候重新選擇方向 vectorprintmatrix vector matrix int d 0 int row...
劍指offer 順時針列印矩陣
輸入乙個矩陣,按照從外向裡以順時針的順序依次列印出每乙個數字。例如 我們可以借助圖形來幫助思考,如下圖 我們可以將列印分為一圈一圈的,對於左圖,6x6的矩陣,最後一圈有4個數字,左上角為 2,2 6 2x2 對於右圖,5x5的矩陣,最後一圈只有乙個數字,左上角也為 2,2 5 2x2 因此我們可將c...