[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都顺利通过。

posted @ 2013-06-08 22:02  Shawnone  阅读(4635)  评论(0编辑  收藏  举报