[LeetCode 124] - 二叉樹最大路徑和(Binary Tree Maximum Path Sum)


問題

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

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

例如:

給出如下二叉樹,

       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 };
maxPathSum

提交后Judge Small和Judge Large都順利通過。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM