Binary Tree Maximum Path Sum
Question
- leetcode: Binary Tree Maximum Path Sum | LeetCode OJ
- lintcode: (94) Binary Tree Maximum Path Sum
Problem Statement
Given a binary tree, find the maximum path sum.
The path may start and end at any node in the tree.
Example
Given the below binary tree:
1
/ \
2 3
return 6
.
题解1 - 递归中仅返回子树路径长度
如题目右侧的四颗半五角星所示,本题属于中等偏难的那一类题。题目很短,要求返回最大路径和。咋看一下感觉使用递归应该很快就能搞定,实则不然,因为从题目来看路径和中不一定包含根节点!也就是说可以起止于树中任一连通节点。
弄懂题意后我们就来剖析剖析,本着由简入难的原则,我们先来分析若路径和包含根节点,如何才能使其路径和达到最大呢?选定根节点后,路径和中必然包含有根节点的值,剩下的部分则为左子树和右子树,要使路径和最大,则必然要使左子树和右子树中的路径长度都取最大。
Warning 注意区分包含根节点的路径和(题目要的答案)和左子树/右子树部分的路径长度(答案的一个组成部分)。路径和=根节点+左子树路径长度+右子树路径长度
-10
/ \
2 -3
/ \ / \
3 4 5 7
如上所示,包含根节点-10
的路径和组成的节点应为4 -> 2 -> -10 <- -3 <- 7
, 对于左子树而言,其可能的路径组成节点为3 -> 2
或4 -> 2
, 而不是像根节点的路径和那样为3 -> 2 <- 4
. 这种差异也就造成了我们不能很愉快地使用递归来求得最大路径和。
我们使用分治的思想来分析路径和/左子树/右子树,设 $$f(root)$$ 为root
的子树到root
节点(含)路径长度的最大值,那么我们有
$$f(root) = root->val + \max (f(root->left), ~f(root->right))$$
递归模型已初步建立起来,接下来就是分析如何将左右子树的路径长度和最终题目要求的「路径和」挂钩。设 $$g(root)$$ 为当「路径和」中根节点为root
时的值,那么我们有
$$g(root) = root->val + f(root->left) + f(root->right)$$
顺着这个思路,我们可以遍历树中的每一个节点求得 $$g(node)$$ 的值,输出最大值即可。如果不采取任何记忆化存储的措施,其时间复杂度必然是指数级别的。嗯,先来看看这个思路的具体实现,后续再对其进行优化。遍历节点我们使用递归版的前序遍历,求单边路径长度采用递归。
题解2 - 递归中同时返回子树路径长度和路径和
# Definition for a binary tree node
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# @param root, a tree node
# @return an integer
def maxsum(self, root):
if root == None: return 0
sum = root.val
lmax = 0; rmax = 0
if root.left:
lmax = self.maxsum(root.left)
if lmax > 0:
sum += lmax
if root.right:
rmax = self.maxsum(root.right)
if rmax > 0:
sum += rmax
if sum > Solution.max: Solution.max = sum
return max(root.val, max(root.val + lmax, root.val + rmax))
def maxPathSum(self, root):
Solution.max = -10000000
if root == None: return 0
self.maxsum(root)
return Solution.max
"""
Definition of TreeNode:
class TreeNode:
def __init__(self, val):
this.val = val
this.left, this.right = None, None
"""
class Solution:
"""
@param root: The root of binary tree.
@return: An integer
"""
def maxPathSum(self, root):
maxSum, _ = self.maxPathHelper(root)
return maxSum
def maxPathHelper(self, root):
if root is None:
return -sys.maxint, 0
left = self.maxPathHelper(root.left)
right = self.maxPathHelper(root.right)
maxpath = max(left[0], right[0], root.val + left[1] + right[1])
single = max(left[1] + root.val, right[1] + root.val, 0)
return maxpath, single