Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
For example:
Given the below binary tree,
1 / 2 3
Return 6
.
关键点1:
分析:http://fisherlei.blogspot.com/2013/01/leetcode-binary-tree-maximum-path-sum.html
For each node like following, there should be four ways existing for max path:
1. Node only (因为本题中的节点可能是负值!)
2. L-sub + Node
3. R-sub + Node
4. L-sub + Node + R-sub
Keep trace the four path and pick up the max one in the end.
关键点2:明确递归函数的返回值是什么:这本题中返回值表示通过root节点能走到root的parent的最大和,这个值作为返回对象返给调用父函数。
树结构显然用递归来解,解题关键:
1、对于每一层递归,只有包含此层树根节点的值才可以返回到上层。否则路径将不连续。
2、返回的值最多为根节点加上左右子树中的一个返回值,而不能加上两个返回值。否则路径将分叉。
在这两个前提下有个需要注意的问题,最上层返回的值并不一定是满足要求的最大值,
因为最大值对应的路径不一定包含root的值,可能存在于某个子树上。
因此解决方案为设置全局变量maxSum,在递归过程中不断更新最大值。
参考:http://www.xuebuyuan.com/2102572.html (了解返回值与求得的最大值不是一样的)
因为要计算任意path的最大值, 根据题意要求,可以理解为可以用一笔画完(不重复,不走回头路)的曲线覆盖的节点就算是一条合法的path。
用一个helper函数getSum(TreeNode* root, int &ret)来中序遍历整个tree,这个函数返回值是以root为根的子树的包含root节点本身的一个序列的最大值,ret的值是到遍历完当前root指定的子树后,已经出现过的所有子序列中的最大值; 这样一来,返回至可以被用来继续计算当前root的父亲节点所在的子树的最大值;
这样一来,每处理一个节点的时候可以得到包含其左孩子的一个最大合l,一个包含其右孩子的最大和r, 在考虑节点本身的值val, 我们可以得到4种不同的组合
(l + val), (r + val), val, (l + val + r), 这四个值取最大的一个来和传入的此前最大的值ret比较并赋值(如果ret小于当前算出的最大值); 返回值则是max(l, r,0) + val (必须包含当前节点值的一个最大和值)。
C++实现代码:
#include<iostream> #include<new> #include<climits> using namespace std; //Definition for binary tree struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: int maxPathSum(TreeNode *root) { if(root==NULL) return 0; int res=INT_MIN; helper(root,res); return res; } int helper(TreeNode *root,int &res) { if(root==NULL) return 0; int left=helper(root->left,res); int right=helper(root->right,res); int val=root->val; if(left>0) val+=left; if(right>0) val+=right; int ret=max(root->val,root->val+max(left,right)); //res指的是所有root中的所有路径的最大值,不一定以root为根,因此不能返回给上层 res=max(res,max(val,ret)); //返回值表示的是以root为根的最大值 return ret; } void createTree(TreeNode *&root) { int i; cin>>i; if(i!=0) { root=new TreeNode(i); if(root==NULL) return; createTree(root->left); createTree(root->right); } } }; int main() { Solution s; TreeNode *root; s.createTree(root); cout<<s.maxPathSum(root)<<endl; }
注意其中ret和res的区别,其实res是包含ret的最大值的,但是res不能用了返回给上层,如果即选择了root的左子树又选择了右子树,则如果返回上层,会出现分支的情况。
简单一点的写法:
class Solution { public: int maxPathSum(TreeNode *root) { int ret = INT_MIN; getSum(root, ret); return ret; } private: int getSum(TreeNode *node, int &ret) { if (node == NULL) return 0; int l = getSum(node->left, ret); int r = getSum(node->right, ret);
//cret是返回值,如果要返回到上层节点root,cret要么是root的左子树与root的和或者是右子树与root的和或者直接就是root的值,取三者中较大的 int cret = max(node->val, max(l, r) + node->val);
//ret维持一个局部的最大值 ret = max(ret, max(cret, l + r + node->val)); return cret; } };