题目描述
给定一个非空二叉树,找到路径权值和的最大值。
在这道题目中,路径是指从树中某个节点开始,沿着树中的边走,走到某个节点为止,路过的所有节点的集合。
路径的权值和是指路径中所有节点的权值的总和。
样例1
输入:[1,2,3]
1
/ \
2 3
输出:6
样例2
输入:[-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
输出:42
算法
(递归,树的遍历) $O(n^2)$
树中每条路径,都存在一个离根节点最近的点,我们把它记为割点,用割点可以将整条路径分为两部分:从该节点向左子树延伸的路径,和从该节点向右子树延伸的部分,而且两部分都是自上而下延伸的。如下图所示,蓝色的节点为割点:
我们可以递归遍历整棵树,递归时维护从每个节点开始往下延伸的最大路径和。
对于每个点,递归计算完左右子树后,我们将左右子树维护的两条最大路径,和该点拼接起来,就可以得到以这个点为割点的最大路径。
然后维护从这个点往下延伸的最大路径:从左右子树的路径中选择权值大的一条延伸即可。
时间复杂度分析:每个节点仅会遍历一次,所以时间复杂度是 $O(n)$。
C++ 代码
/**
* 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 ans;
int maxPathSum(TreeNode* root) {
ans = INT_MIN;
dfs(root);
return ans;
}
int dfs(TreeNode* root)
{
if (!root) return 0;
int left = max(0, dfs(root->left));
int right = max(0, dfs(root->right));
ans = max(ans, left + root->val + right);
return root->val + max(left, right);
}
};
yls,我想问下如果让打印最长路径是什么的话怎么做呢。
代码这么写为什么不对啊?
看代码秒懂,自己写了半天没写出来
如果左右子树权值一样怎么处理。。。
树的直径?
y总tql,怎么才能像y总一样灵活自如(信手拈来)的写出递归程序^_^
首先你得拿个金牌,其次再保送个北大,这样可能就有y总一半强了哈哈
^_^
Y总,为什么主函数的dfs没有返回值?不是int的返回值么?
返回值可以不用。
y总,为什么如果左右子树都是负数的话,就都变成0?
int left = max(0, dfs(root->left));
int right = max(0, dfs(root->right));
对,那么经过当前节点的最大路径和就是 root.val。
往下走的最大值是负数,那还不如不往下走,不往下走是0。
这东西就困难了?
这是leetcode给的难度,在面试题里算法难题了。
y总,如果树的深度很大,用递归是不是会栈溢出?怎么解决呢
一般有两种方式: