Binary Tree Maximum Path Sum(二叉树的最大路径和)
题目描述:
题目链接:https://oj.leetcode.com/problems/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 3
Return 6
.
思路:
看完该题描述,第一反应是好难,要找到最大的和最直观的方法是遍历任意两个结点之间的路径,然后计算路径和,这个组合是C(N,2),效率或许还是可以接受,但是实现这种方法需要两次遍历整个树。暂不说这个,就算现在找到了遍历全部组合的方法,那么处理两个点之间的路径又该如何,当然应该是可以寻找两个结点的最近共公父结点(这个应该也算一个子问题,也应该有自己的时间复杂度,而且是在前一个循环之内的),这就又增加了算法的时间复杂度。
另外的思路将原始问题分解成另外的子问题,可以想想如果这个最大和的路P存在,那么一定存在一个结点距离树根最近,也就是前面说的那个两个结点的最近公共父结点,不妨用coroot表示这个结点。那么所求的路径P肯定是在以coroot为根的原始树的子树中,并且经过根结点,如此就可以将问题变成了求解经过根结点的路径和最大的路径,如果对原始树中的全部结点都进行同样的计算,之后比较其中最大的就是最终的解。
那么转换之后有什么好处呢?让我们把最终的路径分成三部分:子树根的左子树中的一段PL,根结点coroot,以及子树根结点的右子树中的一段。
现在问题就变成了求取一个树中到根结点的路径和的最大值。这个结构就变成了很容易使用递归的情况,因为子问题都是求取一棵树中到根结点路径和的最大值。
因此我们可以写出代码如下:
/**
* 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;
}
if (root->left == NULL && root->right == NULL)
{
return root->val;
}
//We can find the farthest point from the root
//map<TreeNode * , int>
int res = -9999999999;
TreeNode * cur = root;
queue<TreeNode * > levelSeache;
levelSeache.push(cur);
while(!levelSeache.empty()){
TreeNode * tem = levelSeache.front();
levelSeache.pop();
if (tem->left != NULL)
{
levelSeache.push(tem->left);
}
if (tem -> right != NULL)
{
levelSeache.push(tem->right);
}
int sumL = farthestPoint(tem->left);
int sumR = farthestPoint(tem->right);
int sumMax = 0;
sumMax += sumL>0? sumL : 0;
sumMax += sumR>0? sumR : 0;
sumMax += tem->val;
if (res < sumMax)
{
res = sumMax;
}
}
return res;
}
int farthestPoint(TreeNode * root){
int res = 0;
if(root == NULL) return res;
if(root->left == NULL && root->right == NULL)
{
res = root->val;
return res;
}
int sumLeft = farthestPoint(root->left) ;
int sumRight = farthestPoint(root->right) ;
sumLeft = sumLeft>=0 ? sumLeft + root->val : root->val;
sumRight = sumRight >= 0 ? sumRight + root->val : root->val;
res += ((sumLeft>sumRight) ? sumLeft : sumRight);
return res;
}
};
但是这段代码虽然可以得到正确答案,但是提交会超时,原因是显而易见的,递归次数太多。我们可以使用备忘录记录那些已经算过的值,那么应该记录什么值呢,我们只需要记录每个结点的最大路径和值就可以满足我们题目的要求。下面是我添加了两个map的代码,仅仅是对上面代码进行了一点点修改,最终AC。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
map<TreeNode*, bool> flag;
map<TreeNode*, int> sumTree;
int maxPathSum(TreeNode * root){
if (root == NULL)
{
return 0;
}
if (root->left == NULL && root->right == NULL)
{
return root->val;
}
//We can find the farthest point from the root
//map<TreeNode * , int>
int res = -99999999;
TreeNode * cur = root;
queue<TreeNode * > levelSeache;
levelSeache.push(cur);
while(!levelSeache.empty()){
TreeNode * tem = levelSeache.front();
levelSeache.pop();
if (tem->left != NULL)
{
levelSeache.push(tem->left);
}
if (tem -> right != NULL)
{
levelSeache.push(tem->right);
}
int sumL = farthestPoint(tem->left);
int sumR = farthestPoint(tem->right);
int sumMax = 0;
sumMax += sumL>0? sumL : 0;
sumMax += sumR>0? sumR : 0;
sumMax += tem->val;
if (res < sumMax)
{
res = sumMax;
}
}
return res;
}
int farthestPoint(TreeNode * root){
int res = 0;
if(root == NULL) return res;
if (flag[root])
{
return sumTree[root];
}
if(root->left == NULL && root->right == NULL)
{
res = root->val;
flag[root] = true;
sumTree[root] = res;
return res;
}
int sumLeft = farthestPoint(root->left) ;
int sumRight = farthestPoint(root->right) ;
sumLeft = sumLeft>=0 ? sumLeft + root->val : root->val;
sumRight = sumRight >= 0 ? sumRight + root->val : root->val;
res += ((sumLeft>sumRight) ? sumLeft : sumRight);
flag[root] = true;
sumTree[root] = res;
return res;
}
};