动态规划—124. 二叉树中的最大路径和
- 题目描述
- 前言
- 基本思路
- 1. 问题定义
- 路径的限制:
- 2. 理解问题和递推关系
- 核心思路:
- 状态定义:
- 递归公式:
- 3. 解决方法
- 递归 + 动态规划方法
- 伪代码:
- 4. 进一步优化
- 5. 小总结
- Python代码
- Python代码解释
- C++代码
- C++代码解释
- 总结
题目描述
前言
二叉树中的最大路径和 是一个涉及到二叉树的经典动态规划问题。给定一棵二叉树,其中每个节点包含一个整数值,求出从任意节点开始到任意节点结束(路径上至少包含一个节点)的路径中的最大和。路径可以从树中的任意节点开始和结束,且必须沿着父节点和子节点之间的边走。
该问题的难点在于路径可以穿过树的任意部分,因此我们需要同时考虑左右子树的贡献,并且动态更新最大路径和。
基本思路
1. 问题定义
给定一棵二叉树,其中每个节点包含一个整数值,要求找到一条路径,使路径上的节点值之和最大。路径至少包含一个节点,且不一定经过根节点。
路径的限制:
- 路径可以从任意节点开始,到任意节点结束。
- 路径必须连续,并且只能沿父子节点的连接边进行。
2. 理解问题和递推关系
核心思路:
我们可以通过递归的方式来求解该问题。对于每个节点,我们有两种情况:
- 路径经过当前节点:我们可以将当前节点作为路径中的一部分,同时从左右子节点中选择贡献较大的部分。
- 路径不经过当前节点:在递归的过程中,每个节点的最大贡献值可以用来更新全局最大路径和。
状态定义:
-
递归函数
max_gain(node)
:- 该函数的作用是计算从当前节点出发的最大贡献值,也就是从当前节点延伸出去的路径的最大和。
- 对于每个节点
node
,它的最大贡献值等于:
max_gain ( n o d e ) = max ( 0 , max_gain ( n o d e . l e f t ) ) + max ( 0 , max_gain ( n o d e . r i g h t ) ) + n o d e . v a l \text{max\_gain}(node) = \max(0, \text{max\_gain}(node.left)) + \max(0, \text{max\_gain}(node.right)) + node.val max_gain(node)=max(0,max_gain(node.left))+max(0,max_gain(node.right))+node.val
其中,max_gain(node.left)
和max_gain(node.right)
分别表示左子树和右子树的最大贡献值,若某一侧的贡献值为负,则不应选择该侧路径(故取最大值和 0 进行比较)。
-
全局最大路径和
max_sum
:- 我们需要维护一个全局变量
max_sum
,用于存储遍历过程中遇到的最大路径和。 - 每次计算当前节点的路径和时,如果其和大于
max_sum
,则更新max_sum
。
- 我们需要维护一个全局变量
递归公式:
-
对于每个节点
node
,路径和的更新公式为:
price_newpath = n o d e . v a l + max ( 0 , max_gain ( n o d e . l e f t ) ) + max ( 0 , max_gain ( n o d e . r i g h t ) ) \text{price\_newpath} = node.val + \max(0, \text{max\_gain}(node.left)) + \max(0, \text{max\_gain}(node.right)) price_newpath=node.val+max(0,max_gain(node.left))+max(0,max_gain(node.right))
price_newpath
表示从左子树、右子树延伸到该节点的新路径的和。 -
更新全局最大路径和:
max_sum = max ( max_sum , price_newpath ) \text{max\_sum} = \max(\text{max\_sum}, \text{price\_newpath}) max_sum=max(max_sum,price_newpath) -
返回从当前节点延伸到它父节点的最大贡献值:
return value = n o d e . v a l + max ( max_gain ( n o d e . l e f t ) , max_gain ( n o d e . r i g h t ) ) \text{return value} = node.val + \max(\text{max\_gain}(node.left), \text{max\_gain}(node.right)) return value=node.val+max(max_gain(node.left),max_gain(node.right))
3. 解决方法
递归 + 动态规划方法
- 定义递归函数
max_gain(node)
来计算从当前节点出发的最大贡献值。 - 在递归的过程中,动态更新全局最大路径和。
- 最终返回
max_sum
,即全局最大路径和。
伪代码:
function maxPathSum(root):
max_sum = -infinity
function max_gain(node):
if node is None:
return 0
left_gain = max(max_gain(node.left), 0)
right_gain = max(max_gain(node.right), 0)
price_newpath = node.val + left_gain + right_gain
max_sum = max(max_sum, price_newpath)
return node.val + max(left_gain, right_gain)
max_gain(root)
return max_sum
4. 进一步优化
- 递归方式:通过后序遍历的方式(即先处理子节点,再处理父节点),以确保每个节点的最大路径和能正确地递归计算。
- 时间复杂度:该算法的时间复杂度为
O(n)
,其中n
为节点的个数。
5. 小总结
- 问题思路:通过后序遍历递归求解,每个节点的最大路径和可以由其左子树和右子树的最大贡献值来决定。
- 核心公式:路径和更新公式
price_newpath = node.val + left_gain + right_gain
,最大贡献值的返回公式return node.val + max(left_gain, right_gain)
。 - 时间复杂度:时间复杂度为
O(n)
,适合处理中等规模的树形结构。
以上就是二叉树中的最大路径和问题的基本思路。
Python代码
class Solution:
def maxPathSum(self, root: TreeNode) -> int:
self.max_sum = float('-inf') # 初始化最大路径和为负无穷
# 递归函数,计算当前节点的最大贡献值
def max_gain(node):
if not node:
return 0
# 递归计算左右子树的最大贡献值,负数直接取0
left_gain = max(max_gain(node.left), 0)
right_gain = max(max_gain(node.right), 0)
# 当前节点的路径和
price_newpath = node.val + left_gain + right_gain
# 更新全局最大路径和
self.max_sum = max(self.max_sum, price_newpath)
# 返回该节点的最大贡献值
return node.val + max(left_gain, right_gain)
# 调用递归函数计算
max_gain(root)
return self.max_sum
Python代码解释
- 初始化:定义全局变量
max_sum
来存储最大路径和,初始值设为负无穷。 - 递归计算:使用递归函数
max_gain(node)
,计算每个节点的最大贡献值,并动态更新max_sum
。 - 返回结果:最终返回
max_sum
,即二叉树中的最大路径和。
C++代码
class Solution {
public:
int max_sum = INT_MIN; // 初始化最大路径和为负无穷
// 递归函数,计算当前节点的最大贡献值
int max_gain(TreeNode* node) {
if (!node) return 0;
// 递归计算左右子树的最大贡献值,负数直接取0
int left_gain = max(max_gain(node->left), 0);
int right_gain = max(max_gain(node->right), 0);
// 当前节点的路径和
int price_newpath = node->val + left_gain + right_gain;
// 更新全局最大路径和
max_sum = max(max_sum, price_newpath);
// 返回该节点的最大贡献值
return node->val + max(left_gain, right_gain);
}
int maxPathSum(TreeNode* root) {
max_gain(root);
return max_sum;
}
};
C++代码解释
- 初始化:定义全局变量
max_sum
来存储最大路径和,初始值设为INT_MIN
。 - 递归计算:使用递归函数
max_gain(node)
,计算每个节点的最大贡献值,并动态更新max_sum
。 - 返回结果:最终返回
max_sum
,即二叉树中的最大路径和。
总结
- 核心思想:通过后序遍历的方式递归求解二叉树中的最大路径和。每个节点的最大贡献值由左右子树的贡献值决定,同时更新全局最大路径和。
- 动态规划的递归形式:利用递归求解左右子树的最大贡献值,再决定当前节点是否选择左子树、右子树的贡献来形成新的路径。
- 时间复杂度:时间复杂度为
O(n)
,每个节点只访问一次,适合处理中等规模的二叉树问题。