vlambda博客
学习文章列表

124. 二叉树中的最大路径和

优质项目,及时送达

-----

124. 二叉树中的最大路径和[1]

题目描述:

路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径至少包含一个节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点root,返回其最大路径和。

示例 1:

示例 1
输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

示例 2:

示例 2
输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42

方法一:递归

思路与算法

首先,考虑实现一个简化的函数maxGain(node),该函数计算二叉树中的一个节点的最大贡献值,具体而言,就是在以该节点为根节点的子树中寻找以该节点为起点的一条路径,使得该路径上的节点值之和最大。

具体而言,该函数的计算如下。

  • 空节点的最大贡献值等于 00。

  • 非空节点的最大贡献值等于节点值与其子节点中的最大贡献值之和(对于叶节点而言,最大贡献值等于节点值)。

代码

java-1:

class Solution {
    
    private int ret = Integer.MIN_VALUE;
    
    public int maxPathSum(TreeNode root) {
        /**
        对于任意一个节点, 如果最大和路径包含该节点, 那么只可能是两种情况:
        1. 其左右子树中所构成的和路径值较大的那个加上该节点的值后向父节点回溯构成最大路径
        2. 左右子树都在最大路径中, 加上该节点的值构成了最终的最大路径
        **/

        getMax(root);
        return ret;
    }
    
    private int getMax(TreeNode r) {
        if(r == nullreturn 0;
        int left = Math.max(0, getMax(r.left)); // 如果子树路径和为负则应当置0表示最大路径不包含子树
        int right = Math.max(0, getMax(r.right));
        ret = Math.max(ret, r.val + left + right); // 判断在该节点包含左右子树的路径和是否大于当前最大路径和
        return Math.max(left, right) + r.val;//该节点所能贡献的最大值
    }
}

Java-2

class Solution {
    int maxSum = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        maxGain(root);
        return maxSum;
    }

    public int maxGain(TreeNode node) {
        if (node == null) {
            return 0;
        }
        
        // 递归计算左右子节点的最大贡献值
        // 只有在最大贡献值大于 0 时,才会选取对应子节点
        int leftGain = Math.max(maxGain(node.left), 0);
        int rightGain = Math.max(maxGain(node.right), 0);

        // 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
        int priceNewpath = node.val + leftGain + rightGain;

        // 更新答案
        maxSum = Math.max(maxSum, priceNewpath);

        // 返回节点的最大贡献值
        return node.val + Math.max(leftGain, rightGain);
    }
}

Python:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

import sys

class Solution:
    
    result = -sys.maxsize-1
    
    def maxPathSum(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """

        self.maxValue(root)
        return self.result
    
    """
    最大路径和:根据当前节点的角色,路径和可分为两种情况:
    一:以当前节点为根节点
    1.只有当前节点
    2.当前节点+左子树
    3.当前节点+右子书
    4.当前节点+左右子树    
    这四种情况的最大值即为以当前节点为根的最大路径和
    此最大值要和已经保存的最大值比较,得到整个树的最大路径值
    
    二:当前节点作为父节点的一个子节点
    和父节点连接的话则需取【单端的最大值】
    1.只有当前节点
    2.当前节点+左子树
    3.当前节点+右子书
    这三种情况的最大值    
    """

    def maxValue(self,root):
        if root == None:            
            return 0
        
        leftValue = self.maxValue(root.left)
        rightValue = self.maxValue(root.right)
        
        value1 = root.val
        value2 = root.val + leftValue
        value3 = root.val + rightValue
        value4 = root.val + rightValue + leftValue
        
        #以此节点为根节点的最大值
        maxValue = max([value1,value2,value3,value4])
        
        #当前遍历树的最大值
        self.result = max(maxValue, self.result)
        
        #要和父节点关联,则需要取去除情况4的最大值
        return max([value1,value2,value3])
        

复杂度分析

  • 时间复杂度:O(N)O(N),其中NN是二叉树中的节点个数。对每个节点访问不超过 22 次。

  • 空间复杂度:O(N)O(N),其中NN是二叉树中的节点个数。空间复杂度主要取决于递归调用层数,最大层数等于二叉树的高度,最坏情况下,二叉树的高度等于二叉树中的节点个数。

本质

核心代码,后续遍历

int ans = INT_MIN;
int getMax(TreeNode* root) {
    if (root == nullptr) return 0;
    int left = max(0, getMax(root->left));
    int right = max(0, getMax(root->right));
    ans = max(ans, left + right + root->val);
    return max(left, right) + root->val;
}

参考资料

[1]

124. 二叉树中的最大路径和: https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/