1. 程式人生 > >二叉樹最大路徑和

二叉樹最大路徑和

給出一個二叉樹,找到其中的最大路徑和。

路徑可以從樹中任意一個節點開始和結束。

例如:

給出如下二叉樹,

       1

      / \

    2    3

返回6。

初始思路

為了簡化分析,我們先假設二叉樹中所有節點的值都是正數。通過觀察可以發現,一棵二叉樹的最大路徑,就是其左子樹的最大路徑加上右子樹的最大路徑。看起來可以從根節點出發通過深度優先遞迴來求解:

函式 查詢路徑

   如果是葉子節點,返回葉子節點的值

   如果不是葉子節點

      左子樹路徑和 = 查詢路徑(左子樹)

      右子樹路徑和 = 查詢路徑(右子樹)

      如果左子樹路徑+右子樹路徑和+當前節點值 > 當前最大路徑,更新最大路徑

      返回左子樹路徑+右子樹路徑和+當前節點值

用題目中的簡單例子來驗證,是可以得出答案的。但是使用複雜一點的樹來驗證後就發現其中的問題了,如

              1

           /      \

         2         3

      /      \

    4        5

使用前面的虛擬碼得出的結果是15,但是其實答案應該是11,由3,1,2,5或者2,4,5得到。分析可以發現問題在於計算2,4,5這棵子樹時,它的最長路徑為11,這是正確的。但是當它作為左子樹向父節點返回最長路徑時,因該返回7而不是11。因為從1出發不走重複路徑不可能同時到達4或5的-通常二叉樹節點路徑的定義是每個節點只能訪問一次,通過測試資料也可以驗證題目就是這樣要求的。因此我們需要兩個最大值,一個是當前樹的最大路徑,即前面虛擬碼算出來的那個值;另一個是當前樹向父節點提供的最大路徑,這個值應該是根節點的值加上路徑最長的子樹那邊的最大路徑。我們向上層遞迴函式返回這個值。

好了,現在全是正數的情況解決了。讓我們開始把負數引入。負數引入後,將會導致以下幾個變化:

  • 葉子節點的值也有可能成為最大路徑。在全是正數的情形下,葉子節點的值肯定不可能會是最大路徑,因為加上父節點的值後必然會變大。有了負數以後,這個情況就不成立了,如:

                -1

              /      

            3

        這時最大路徑就是3。

  • 當前樹最大路徑的計算方法。有了負數以後不能簡單的把左子樹返回的值,右子樹返回的值及當前的值相加了。這裡我們把各種情況列舉出來:
    • 當前值為正,子樹返回值都為正:全相加
    • 當前值為正,子樹返回值有一個為正:當前值+正的那個值,因為負值只會讓結果變小。
    • 當前值為正,子樹返回值都是負:只取當前值,負值越加越小。
    • 當前值為負,子樹返回的值都為正:全相加,雖然值會變小,但是沒有當前節點左右就不能聯通。
    • 當前值為負,子樹返回值有一個為正:當前值+正的那個值。
    • 當前值為負,子樹返回值都為負:當前值,負值越加越小。
  • 向父節點提供的最大路徑的計算方法。和當前樹最大路徑計算方法基本一樣。就是仍然要左子樹右子樹的值只能取大的那個。

將上面分析轉換成程式碼,並加入一些細節如沒有左(右)子樹的判斷。請注意由於節點的取值範圍並沒有限定,所以不能使用某個特殊值作為沒有左(右)子樹的標誌。結果如下:

複製程式碼
  1 class Solution {
  2 public:
  3     int maxPathSum(TreeNode *root)
  4     {
  5         if(!root)
  6         {
  7             return 0;
  8         }
  9         
 10         maxSum_ = 0;
 11         firstValue_ = true;
 12         
 13         CountPathSum(root);
 14         
 15         return maxSum_;
 16     }
 17     
 18 private:
 19     int CountPathSum(TreeNode* root)
 20     {
 21         if(root->left == 0 && root->right == 0)
 22         {
 23             if(firstValue_ || root->val > maxSum_)
 24             {
 25                 maxSum_ = root->val;
 26                 firstValue_ = false;
 27             }
 28             return root->val;
 29         }
 30         else
 31         {
 32             int left = 0;
 33             int right = 0;
 34             if(root->left)
 35             {
 36                 left = CountPathSum(root->left);
 37             }
 38             
 39             if(root->right)
 40             {
 41                 right = CountPathSum(root->right);
 42             }
 43             
 44             int currentBest = 0;
 45             int sumInPah = 0;
 46             
 47             if(left > 0 && right > 0)
 48             {
 49                 currentBest = left + right;
 50                 
 51                 sumInPah = left > right ? left : right;
 52             }
 53             else if(left > 0)
 54             {
 55                 currentBest = left;
 56                 sumInPah = left;
 57             }
 58             else if(right > 0)
 59             {
 60                 currentBest = right;
 61                 sumInPah = right;
 62             }
 63             else
 64             {
 65                 if(!root->left)
 66                 {
 67                     currentBest = right;
 68                 }
 69                 else if(!root->right)
 70                 {
 71                     currentBest = left;
 72                 }
 73                 else
 74                 {
 75                     currentBest = left > right ? left : right;
 76                     
 77                 }
 78                 sumInPah = currentBest;
 79             }
 80             
 81                         //前面已做只取正值的處理,如果還小於零說明兩個都是負數
 82             if(sumInPah < 0)
 83             {
 84                 sumInPah = root->val;
 85             }
 86             else
 87             {
 88                 sumInPah += root->val;
 89             }
 90             
 91             if(currentBest < 0)
 92             {
 93                 currentBest = root->val;
 94             }
 95             else
 96             {
 97                 currentBest += root->val;    
 98             }
 99     
100             if(currentBest > maxSum_)
101             {
102                 maxSum_ = currentBest;
103             }
104             
105             return sumInPah;
106         }
107     }
108     
109     int maxSum_;
110     bool firstValue_;
111 };