Binary Tree Maximum Path Sum
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 3Return
6
.Tags: tree, depth-first-search
10/10/2015 udpate
divide-and-conquer approach
o(n) solution, use a fancy recursion function, do two works together.
It returns the path sum starts from root node to nodes below,
res is the current maximum sum path
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: int MININT = 0x8fffffff; int maxPathSum(TreeNode* root) { int res = MININT; pathSum(root, res); return res; } //return the max path sum that starts from root //res is the maximum path sum in this tree int pathSum(TreeNode * root, int& res){ if(root == nullptr) return -1; int left = pathSum(root->left, res); int right = pathSum(root->right, res); int tmp = root->val; tmp = left > 0? tmp + left: tmp; tmp = right > 0? tmp + right: tmp; res = max(res, tmp); return max(max(left, right), 0) + root->val; } };
O(nlogn) solution, not quite efficient, time limit excced.
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: int MININT = 0x80000000; int maxPathSum(TreeNode* root) { if(root == nullptr){ return MININT; } int left = maxPathSum(root->left); int right = maxPathSum(root->right); int leftPath = maxToRootSum(root->left); int rightPath = maxToRootSum(root->right); int tmp = root->val; tmp = leftPath > 0? tmp + leftPath: tmp; tmp = rightPath > 0? tmp + rightPath: tmp; return max(left, max(right, tmp)); } int maxToRootSum(TreeNode * root){ if(root == nullptr) return -1; int left = maxToRootSum(root->left); int right = maxToRootSum(root->right); int tmp = root->val; tmp = max(left, right) > 0? tmp + max(left, right): tmp; return tmp; } };
Tag里没写divide-and-conquer. 但我还是先想到了一个分治的算法.
这道题让我想起数据结构书上,第一章的那个作为引子的,最大子序列问题.我想着把这个树近似成一个多叉数组来处理,这里化用了原书里的第三个分而治之的算法,时间复杂度O(nlogn).但是竟然没让我过!说是超时.我还在想O(n)的算法.或许应该化用书中第四个算法.记得那个算法是O(n)的复杂度.
版本一:O(nlogn),分治算法,超时
需要注意,max只接受两两参数的比较.如果多参数比较的话,需要嵌套max函数.
C++:
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: /** * divide and conque **/ int maxPathSum(TreeNode *root) { int leftSum, rightSum, leftAdjacentSum, rightAdjacentSum; bool isLeftSet = false; bool isRightSet = false; //leaf node if(root->left == NULL && root->right == NULL){ return root->val; } else{ if(root->left != NULL){ isLeftSet = true; leftSum = maxPathSum(root->left); leftAdjacentSum = maxAdjacentPathSum(root->left); } if(root->right != NULL){ isRightSet = true; rightSum = maxPathSum(root->right); rightAdjacentSum = maxAdjacentPathSum(root->right); } //due to the if condition in line 21, either isLeftSet or isRightSet should be true. if(isRightSet == false){ //isLeftSet is true return max(leftSum, max(leftAdjacentSum, 0) + root->val); } else if(isLeftSet == false){ //isRightSet is true return max(rightSum, max(rightAdjacentSum, 0) + root->val); } else{ //both isRightSet and isLeftSet is true //if either the rightAjacentSum or the leftAjacentSum is smaller than 0, discard it. return max(max(leftSum, rightSum), max(leftAdjacentSum, 0) + max(rightAdjacentSum, 0) + root->val); } } } int maxAdjacentPathSum(TreeNode *root){ int maxLeft, maxRight; bool isLeftSet = false; bool isRightSet = true; if(root->left == NULL && root->right == NULL){ return root->val; } if(root->left != NULL){ maxLeft = maxAdjacentPathSum(root->left); isLeftSet = true; } if(root->right != NULL){ maxRight = maxAdjacentPathSum(root->right); isRightSet = true; } if(isRightSet == false){ return max(maxLeft, 0) + root->val; } else if(isLeftSet == false){ return max(maxRight, 0) + root->val; } else{ return max(max(maxRight, maxLeft), 0) + root->val; } } };
一月二十二号晚更新:
找到了时间复杂度为O(n)的办法。其实版本一已经很接近O(n)了,只是我的递归没有写好,maxAdjacentPathSum是多余的,它的工作完全可以合并在maxPathSum里。从结构上也不难发现,它的函数结构和maxPathSum有惊人的相似。
实际上,maxAdjacentSum所需要的信息在maxPathSum的递归时已经得到了。正如数据结构书的第一章介绍递归时所讲,“永远不要把同一个东西计算两次。”
我只是机械性地把两个函数合并在了一起。虽然AC了,但执行效率依旧比第一名有一些差距。不知有没有更有效率的方法?或者用循环来代替递归?
版本二:简化后的分治算法,AC
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class ReturnValue{ public: int maxPathSum; int maxAdjacentSum; ReturnValue(int x, int y):maxPathSum(x), maxAdjacentSum(y){} }; class Solution { public: /** * divide and conquer **/ int maxPathSum(TreeNode *root){ return _maxPathSum(root)->maxPathSum; } ReturnValue * _maxPathSum(TreeNode *root) { int leftSum, rightSum, leftAdjacentSum, rightAdjacentSum; bool isLeftSet = false; bool isRightSet = false; ReturnValue * p; //leaf node if(root->left == NULL && root->right == NULL){ return new ReturnValue(root->val, root->val); } else{ if(root->left != NULL){ isLeftSet = true; p = _maxPathSum(root->left); leftSum = p->maxPathSum; leftAdjacentSum = p->maxAdjacentSum; } if(root->right != NULL){ isRightSet = true; p = _maxPathSum(root->right); rightSum = p->maxPathSum; rightAdjacentSum = p->maxAdjacentSum; } //due to the if condition in line 21, either isLeftSet or isRightSet should be true. if(isRightSet == false){ //isLeftSet is true int thisMaxPathSum = max(leftSum, max(leftAdjacentSum, 0) + root->val); int thisMaxAdjacentSum = max(leftAdjacentSum, 0) + root->val; return new ReturnValue(thisMaxPathSum, thisMaxAdjacentSum); } else if(isLeftSet == false){ //isRightSet is true int thisMaxPathSum = max(rightSum, max(rightAdjacentSum, 0) + root->val); int thisMaxAdjacentSum = max(rightAdjacentSum, 0) + root->val; return new ReturnValue(thisMaxPathSum, thisMaxAdjacentSum); } else{ //both isRightSet and isLeftSet is true //if either the rightAjacentSum or the leftAjacentSum is smaller than 0, discard it. int thisMaxPathSum = max(max(leftSum, rightSum), max(leftAdjacentSum, 0) + max(rightAdjacentSum, 0) + root->val); int thisMaxAdjacentSum = max(max(rightAdjacentSum, leftAdjacentSum), 0) + root->val; return new ReturnValue(thisMaxPathSum, thisMaxAdjacentSum); } } } };