1.實踐題目:數字三角形 算法
2.問題描述:數組
給定一個由 n行數字組成的數字三角形以下圖所示。試設計一個算法,計算出從三角形 的頂至底的一條路徑(每一步可沿左斜線向下或右斜線向下),使該路徑通過的數字總和最大。數據結構
3.算法描述:設計
首先,將這個數字三角形存儲在一個二維數組num[n+1][n+1]中,且採用左下角的直角三角形的方式存儲(第0行和第0列儲存爲0,方便操做)。例如,將PTA上的樣例輸入存儲爲以下所示:遞歸
0 0 0 0 0 0for循環
0 7 0 0 0 0
0 3 8 0 0 0
0 8 1 0 0 0
0 2 7 4 4 0
0 4 5 2 6 5二叉樹
而後,第1行第1列(7)開始從上到下遍歷,並將它置爲它上方的數及左上方的數的較大值與它自身的和:num[i][j] = num[i][j] + max(num[i-1][j-1], num[i-1][j]);循環
遍歷完成後,最後一行的數都是它上面的數的較大值的總和,以PTA的樣例輸入爲例,通過上述操做之後該數組變成:遍歷
0 0 0 0 0 0方法
0 7 0 0 0 0
0 10 15 0 0 0
0 18 16 15 0 0
0 20 25 20 19 0
0 24 30 27 26 24
所以所求的最大路徑就是最後一行的最大值。這裏使用簡單求數組最大值的方法找到了最大值爲30:
int max = 0;
for (int i = 1; i <= n; i++)
if (num[n][i] > max)
max = num[n][i];
3.算法時間及空間複雜度分析:
時間複雜度:該算法在遍歷階段採用了雙層for循環進行遍歷,所以時間複雜度爲O(n^2)。
空間複雜度:該算法是直接在原數組上操做的,所以輔助空間較少,空間複雜度爲O(1)。
4.心得體會(對本次實踐收穫及疑惑進行總結)
這個題目的主要難點在於如何保存數組以及寫出遞推公式。由這個數字三角形的形狀我第一反應是用二叉樹來保存,而後使用中序遍歷或前序遍從來找到最大路徑。但好像沒有預設的二叉樹的數據結構,並且操做也有諸多困難,所以我最後選擇了二維數組。這裏我用行列長度比原長度大1的方式,空出第0行和第0列,主要是爲了遞歸時的方便,不用考慮邊界的問題。好在這道題的遞推公式也不難寫,所以我按本身對動態規劃的印象寫出了num[i][j] = num[i][j] + max(num[i-1][j-1], num[i-1][j])。這道題有一個坑是咱們每每第一反應是「每次分叉都選最大值,那麼結果不就是最大路徑了嗎?」但這實際上是犯了一個常見的錯誤:認爲局部最優解就是總體最優解。例如,樣例輸入中,咱們每次分叉選擇較大值,即7+8+1+7+5=28。但實際上最優解是3+7+8+7+5=30。所以,咱們在解決相似問題的時候,必定要注意這個細節,即局部最優解並不必定等於總體最優解。