1、描述
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列,该路径至少包含一个节点,且不一定经过根节点。
例1:输入:[1, 2, 3]
输出:6
例2:输入:[-10, 9, 20, nil, nil, 15, 7]
输出:42
2、算法
思想:递归求最大路径和,考虑实现一个简化的函数 max_gain(node) 计算它及其子树的最大贡献 即 计算包含这个顶点的最大权值路径
步骤:
1、初始化 max_sum 为最小可能的证书并调用 max_gain(node=root)
2、实现 max_gain(node)检查是继续旧路径还是开始新路径
1)边界情况:如果节点为空,那么最大权值是 0 。
2)对该节点的所有孩子递归调用 max_gain,计算从左右子树的最大权值:left_gain = max(max_gain(node.left), 0) 和 right_gain = max(max_gain(node.right), 0)。
3)检查是维护旧路径还是创建新路径。创建新路径的权值是:price_newpath = node.val + left_gain + right_gain,当新路径更好的时候更新 max_sum。
4)对于递归返回的到当前节点的一条最大路径,计算结果为:node.val + max(left_gain, right_gain)。
示例 [-10, 9, 20, nil, nil, 15, 7] 的示意图:
时间复杂度:O(n)
func maxPathSum(_ root: TreeNode?) -> Int {
/*
递归
*/
var max_sum = Int.min
max_gain(root, &max_sum)
return max_sum
}
private class func max_gain(_ node : TreeNode?, _ max_sum : inout Int)->Int{
if node == nil {
return 0
}
//分别递归计算左右子树的最大路径和
let left_gain = max(max_gain(node?.left, &max_sum), 0)
let right_gain = max(max_gain(node?.right, &max_sum), 0)
//创建新路径的权值
let price_newpath = (node?.val)! + left_gain+right_gain
//如果有更好的路径时,更新最大值
max_sum = max(max_sum, price_newpath)
return (node?.val)! + max(left_gain, right_gain)
}
测试:
let treeN6 = TreeNode(-10)
let treeN7 = TreeNode(9)
let treeN8 = TreeNode(20)
let treeN9 = TreeNode(15)
let treeN10 = TreeNode(7)
treeN6.left = treeN7
treeN6.right = treeN8
treeN7.left = nil
treeN7.right = nil
treeN8.left = treeN9
treeN8.right = treeN10
treeN9.left = nil
treeN9.right = nil
treeN10.left = nil
treeN10.right = nil
print(Algorithm.maxPathSum(treeN6))
let treeN11 = TreeNode(1)
let treeN12 = TreeNode(2)
let treeN13 = TreeNode(3)
treeN11.left = treeN12
treeN11.right = treeN13
print(Algorithm.maxPathSum(treeN11))
测试结果:
42
6