LeetCode(Nov 8 '12):Binary Tree Maximum Path Sum

一道水题又蘑菇了一下午...这水平可咋办...

原题地址:http://leetcode.com/onlinejudge#question_124


题目要求:


题意分析:

给定一棵二叉树,求最大路径和。路径可以从任意节点开始,到任意节点结束,不必从父节点到子节点。

即找到一棵子树,满足以下要求:

        1、该子树中,除了根节点可以有任意多(0、1、2)孩子,其他节点最多有一个孩子。

        2、该子树的路径和是 所有满足要求1的子树的路径和的最大值。

如题中例子给出的,最大值路径就是2---1---3。

方法一、

实例:

             (5)

            /     \
           /       \
        (-5)     (-9)
       /    \        /

      /      \      /
     (6)   (3) (2)
       \     / 
      (5) (4)
              \
              (1)

        以上面这棵二叉树为例,假设要计算以(5)为根节点的子树(路径必须经过节点(5))最大路径和

        令Left=以左子树根节点(-5)为起点的最大值路径的值,Right=以右子树根节点(-9)为起点的最大路径的值

       注意这里的最大路径与题目中不同,这里只能以左右子树的根节点为起点,且每个节点至多有1个孩子节点,若非如此,就会破坏子树条件1,们称这个过程为getMax(root)。

        当Left或Right为负时,将其值赋为0。

        该子树的最大路径的值是Left+Right+root。

计算过程
       Left=getMax(Leftchild(5))
             =getMax(-5)
             =max{(6+5-5),(1+4+3-5)}
             =6;

       Right=getMax(Rightchild(5))
               =getMax(-9)
               = -7;

        Sum=isminus(Left)+isminus(Right)+5
               =6+0+5
               =11;

       则,以(5)为根节点的情况下,最大路径值为11,路径为(5)---(6)---(-5)----(5)。

       我们递归的按以上方法遍历所有的节点,可以发现,当以(-5)为根节点的时候:

       getMax(6)=11;
       getMax(3)=8;
       Sum=11+8+(-5);
              =14;
       此时的子树拥有最大路径值,即14,路径为(5)---(6)---(-5)---(3)---(4)---(1)

       以下代码中,getMax和recurMax均递归实现,recurMax(root)用来递归遍历所有节点,并计算以root为根节点的子树的最大路径和值,并将所得的最大值返回,即题目所求最大路径值。

由于每次递归都要调用getMax,出现了很多重复的计算,在大数据中没能通过。

实现过程如下

class Solution {
public:
	int maxSum;
    int maxPathSum(TreeNode *root) {
		maxSum=~((~((unsigned int)0))>>1);
		recurMax(root);
        return maxSum;
    }
    void recurMax(TreeNode *root)
	{
		int leftMax=getMax(root->left);
		int rightMax=getMax(root->right);
		int cur_sum=(leftMax>0?leftMax:0)+(rightMax>0?rightMax:0)+root->val;//注意要加括号,因为+的优先级比:的要高。
		if(cur_sum>maxSum)maxSum=cur_sum;
		if(root->left!=NULL) recurMax(root->left);
		if(root->right!=NULL) recurMax(root->right);
	}
    int getMax(TreeNode *root)
	{
		if(root==NULL) return 0;
		int left=root->val+getMax(root->left);
		int right=root->val+getMax(root->right);
		return left>right?left:right;
	}
};


方法二、

方法二对方法一进行了优化,只需要对根节点计算一次getMax。并将getMax的值保存在树中。

还是以方法一中的实例为例:

原树:

              (5)

            /     \
           /       \
        (-5)     (-9)
       /    \        /
      /      \      /
     (6)   (3) (2)
       \     / 
      (5) (4)
              \
              (1)

首先对根节点调用一次getMax(root)其作用如方法一所述,同时左右子树的递归返回值中较大且非负的值,与节点值相加,保存在root节点中。

调用结束后的树如下所示:

             (11)

            /       \
           /         \
         (6)       (-7)
        /     \        /
       /       \      /
   (11)     (8) (2)
       \       / 
        (5) (5)
                \
                (1)

        此时,各个节点的值是原节点值加上左右子树的最大路径和中,较大非负者

        再次递归遍历所有节点,计算当前的节点值加上左右子树最大路径和中,较小且非负者(因为较大的已经加过),所得就是当前节点为根节点的子树的最大路径和。

        本次遍历过程中所得的最大值即为题目要求的最大路径和。


实现过程如下:
public:
	int maxSum;
    int maxPathSum(TreeNode *root) {
		maxSum=~((~((unsigned int)0))>>1);
		getMax(root);
		traversel(root);
		//recurMax(root);
        return maxSum;
    }
    void traversel(TreeNode *root)
	{
		if(root!=NULL)
		{
            int left=0,right=0;
			if(root->left!=NULL) left=root->left->val;
			if(root->right!=NULL) right=root->right->val;
			int smaller=left<right?left:right;
			if(smaller<0) smaller=0;
			if((root->val+smaller)>maxSum) maxSum=root->val+smaller;
			traversel(root->left);
			traversel(root->right);
		}
	}
    int getMax(TreeNode *root)
	{
		if(root==NULL) return 0;
		int left=getMax(root->left);
		int right=getMax(root->right);
		int bigger=left>right?left:right;
		if(bigger>0) root->val+=bigger;
		return root->val;
	}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值