**:
題目:輸入乙個矩陣,按照從外向裡以順時針的順序依次列印出每乙個數字。
例如:如果輸入如下矩陣:
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)的乙個圈來分析。
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)
if(numbers == null || columns <= 0 || rows <= 0)
return;
int startx = 0;
int starty = 0;
while(columns > startx * 2 && rows > starty * 2)
printmatrixincircle(numbers, columns, rows, startx, starty);
++startx;
++starty;
接下來我們分析如何在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)
int endx = columns - 1 - startx;
int endy = rows - 1 - starty;
printarowincreasingly(numbers, columns, rows, starty, startx, endx);
if(starty < endy)
printacolumnincreasingly(numbers, columns, rows, endx, starty + 1, endy);
if(startx < endx && starty < endy)
printarowdecreasingly(numbers, columns, rows, endy, endx - 1, startx);
if(startx < endx && starty < endy - 1)
printacolumndecreasingly(numbers, columns, rows, startx, endy - 1, starty + 1);
接下來我們考慮如何列印一行或者一列。這對我們來說不是一件很難的事情。以函式printarowincreasingly為例,我們只需要乙個迴圈,把行號為starty,列號從startx到endx的所有數字依次從陣列中取出來並逐個列印就行了,對應的**是:
void printarowincreasingly(int** numbers, int columns, int rows,
int y, int firstx, int lastx)
for(int i = firstx; i <= lastx; ++i)
int number = *(*(numbers + y) + i);
printf("%d\t", number);
剩下的三個函式與此類似,**依次如下:
void printacolumnincreasingly(int** numbers, int columns, int rows,
int x, int firsty, int lasty)
for(int i = firsty; i <= lasty; ++i)
int number = *(*(numbers + i) + x);
printf("%d\t", number);
void printarowdecreasingly(int** numbers, int columns, int rows,
int y, int firstx, int lastx)
for(int i = firstx; i >= lastx; --i)
int number = *(*(numbers + y) + i);
printf("%d\t", number);
void printacolumndecreasingly(int** numbers, int columns, int rows,
int x, int firsty, int lasty)
for(int i = firsty; i >= lasty; --i)
int number = *(*(numbers + i) + x);
printf("%d\t", number);
3 5 力扣順序列印矩陣
思路 1 規定4個方向陣列 決定下一次的前進方向 2 建立訪問陣列,標記每個陣列是否訪問過 注意改變前進方向的條件 下乙個陣列行超限 列超限 len 0 下乙個位置遍歷過 class solution int row matrix.length int col matrix 0 length int...
按「之」字形順序列印矩陣(演算法)
列印結果為 4,5,6,1,6,6,9,3,7。要求額外空間複雜度為o 1 演算法思想 根據上例容易觀察出之字形可以拆分成列印上圖直線上的數字,只需將列印方向改變就可以滿足題目要求。設定兩個初始點a和b,同時讓點a向右移動,點b向下移動,當a移動到右邊界時再繼續向下移動,當b移動到下邊界時再向右移動...
Algorithm 順序列印矩陣 美團四面
順時針列印矩陣 思路 1.首先判斷迴圈條件 每次一圈開始時,左上角橫縱座標一樣,所以可以作為迴圈條件col 2 start,row 2 start 2.列印每一圈 a.第一步總是要打的 b.第二步需要有兩行才進行 c.第三步至少兩行兩列 d.第四步至少三行兩列 include stdafx.h in...