螺旋矩陣是乙個nxn的方陣,其中元素為自然數,但像螺旋方向一樣遞增。舉例如下:
若n = 3,螺旋矩陣為:
1 2 3若n = 4,螺旋矩陣為:8 9 4
7 6 5
1 2 3 412 13 14 5
11 16 15 6
10 9 8 7
若n = 5,螺旋矩陣是:
1 2 3 4 5那麼如何列印這樣的矩陣呢?當然它的規律很簡單,直接的方法就是先申請乙個矩陣,然後按螺旋方向填入相應的元素,填充完畢後再列印出來。它的時間按複雜為o(n2),已經是最優的(為什麼?)。空間複雜度也為o(n2)。似乎已經很好了。16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
但是還不夠好。
按照矩陣規律填充元素時,我們是隨機訪問矩陣元素的(如果可以按順序訪問,根本不用先存起來再列印)。隨機訪問記憶體,效率當然不高。所以即使時間複雜度已為最優,但那只是理論上的最優,在實踐中表現並不一定就好。
假如能根據行列號直接計算出對應的矩陣元素就好了。當n給定後,這個矩陣就已經唯一確定了,那麼每乙個元素也是確定的。也就是說,每乙個位置放什麼元素僅僅取決於n。因此我們可以找到乙個函式element(i, j),將行號i和列號j對映成對應這個行列號的元素。當然這個函式肯定不是乙個簡單的函式,不是一眼就可以看出來的,但也並不是不可能。
現在我們就來考查一下這個矩陣有什麼特點。注意觀察一下螺旋矩陣的最外層,它的左上角的元素是最小的,然後沿順時針方向遞增,就如同乙個環一樣(比如n為4時,1, 2, ..., 12就是最外面一層環)。再注意一下裡面一層,也是一樣,順時針方向遞增的乙個環(比如n為4時,13, 14, 15, 16就是裡面一層環)。以此類推,環裡面還有一層環(n為4時有2層環,n為5時有3層環,最裡面一層只有乙個元素25),實際上是乙個圓環套圓環結構。每一圓環最關鍵的元素就是左上角的那乙個元素。只要知道了這個元素,再加上這個正方形環的邊長就可以計算出剩下的元素。設左上角元素為a,邊長為l(ell),也就是邊上有幾個元素,並假設左上角的行號和列號均為0,其它元素的行號和列號都以它作參考,計算方法如下所示:
1. 若i == 0,element(i, j) = a + j;
2. 否則若j == 0,element(i, j) = a + 4(l-4) - (i-1) - 1;
3. 否則若i == l-1,element(i, j) = a + 4(l-4) - (l-2) - 1 - j;
4. 否則element(i, j) = a + l - 1 + i;
剩下的問題就是如何確定左上角的元素,以及當前環在第幾層(最外層是第0層,往裡面依次遞增)。這些都好辦。**如下:
其實這種方法不僅可以用於這種矩陣,對於其它有各種規律的矩陣也可以用這種方法,關鍵是找出那個函式的定義。推而廣之,許多問題實際上在數學上都可以找到這種簡單答案(所謂簡單答案,我指的是類似於級數求和的閉式(closed form),不用遞迴或迴圈計算出答案,而是在有限的步驟之內算出答案。所謂有限是指與問題規模無關。像上面的問題,計算步驟就與矩陣元素個數無關),我們應當盡量地去找這種簡單的答案,而不是用計算機模擬求解。比如約瑟夫(josephus)環問題,有乙個漂亮的簡單答案,在常量時間內算出,根本不需用鍊錶或陣列模擬。當然,也有許多問題沒有這麼漂亮的解法,只好用計算機模擬求解,不過最好還是盡量想辦法找到這種簡單的解法。
列印螺旋矩陣
首先,看一下螺旋矩陣的樣子.如下圖 求螺旋陣列的 如下 dev cpp平台 include using namespace std int alloc mat int round 動態二維陣列的分配 void del mat int mat,int round 刪除動態分配的二維陣列 void pr...
列印螺旋矩陣(遞迴解法)
求職過程遇到的一道面試題,當時沒有做出來,回來想出幾種方法,其中大多是 蠻力 解法,不得不陷入一堆的i j 迴圈之中。最後想出一種遞迴解法,現記錄如下。題目如下 輸入 n,列印 n n 螺旋矩陣 比如 n 3 列印 1 2 3 8 9 4 7 6 5 n 4 列印 1 2 3 4 12 13 14 ...
列印螺旋矩陣(遞迴解法)
求職過程遇到的一道面試題,當時沒有做出來,回來想出幾種方法,其中大多是 蠻力 解法,不得不陷入一堆的i j 迴圈之中。最後想出一種遞迴解法,現記錄如下。題目如下 輸入n,列印 n n 螺旋矩陣 比如 n 3,列印 1 2 3 8 9 4 7 6 5 n 4,列印 1 2 3 4 12 13 14 5...