解法一:基于分解子问题思维模式的递归
最小子问题结构:考虑这样一个二叉树单元
- a 作为当前root,与更上层的父节点相连接
- b, c 作为左右子节点,与各自的左右子树中最大路径和的子节点相连接
那么,现在这个二叉树单元的最大路径和答案就在下面3选1:
- 左分支:b + a(+ a的父节点)
- 右分支:c + a (+ a的父节点)
- 左中右:b + a + c(不再连接a的更上层父节点)
情况1和2,可以分解子问题,递归,选择较大分支
但是情况3无法递归,我们可以用一个全局变量来记录,因为每当我们遍历到一个节点root时,我们能通过递归获取到其左右子树计算好的各自最大路径和了,这时候我们再算一下 left->root->right 这条路径和,更新到一个全局最大和变量中。
注意:节点值可能为负数,答案是要求最大值,那么遇到负数肯定是舍弃。但是,无论上面哪种情况,都需要经过 a,因此 a即使为负数也不能直接舍弃,我们定义全局最大和辅助变量的初始值采用minInt,才能保证和负数 a也正确比较。
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func maxPathSum(root *TreeNode) int {
if root == nil{
return 0
}
res := math.MinInt
_ = maxRootSum(root, &res)
return res
}
// maxRootSum()返回经过root的单边分支最大和,即左、右分支中路径和较大值+当前root节点值
// 同时,还要考虑左中右的一种路径,借助一个变量记录在递归时记录好全局最大和
func maxRootSum(root *TreeNode, maxPathSum *int) int{
if root == nil{
return 0
}
//计算左边分支最大值,左边分支如果为负数还不如不选择
leftMax := max(0, maxRootSum(root.Left, maxPathSum))
//计算右边分支最大值,右边分支如果为负数还不如不选择
rightMax := max(0, maxRootSum(root.Right, maxPathSum))
//考虑左中右这条路径,left->root->right 路径和与已经计算过的全局最大和比较
*maxPathSum = max(*maxPathSum, root.Val + leftMax + rightMax)
// 返回经过当前root的单边分支最大和,给当前root的父节点递归计算使用
return root.Val + max(leftMax, rightMax)
}
func max(a, b int) int{
if a > b {
return a
}
return b
}