leetcode
leetcode 2951 ~ 3000
二叉树中的最大路径和

二叉树中的最大路径和

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 44 ms, 内存: 21.0 MB


/*
 * 思路:
 * 我们需要找到二叉树中的最大路径和。路径可以从任何节点开始,到任何节点结束,且每个节点至多出现在路径中一次。
 * 使用递归的方法来解决这个问题。我们定义一个辅助函数 maxGain(node),它计算从节点 node 出发的最大贡献值。
 * 对于每个节点,考虑两种情况:
 * 1. 当前节点独立成一个路径的起点,那么最大路径和是 node.val + maxGain(node.left) + maxGain(node.right)
 * 2. 当前节点作为上一级路径的一部分,那么最大贡献值是 node.val + max(maxGain(node.left), maxGain(node.right))
 * 
 * 在递归过程中,我们会不断更新全局的最大路径和。
 * 
 * 这里使用Java Stream API来简化代码
 */

import java.util.stream.Stream;

class Solution {
    private int maxSum = Integer.MIN_VALUE;
    
    public int maxPathSum(TreeNode root) {
        maxGain(root);
        return maxSum;
    }
    
    private int maxGain(TreeNode node) {
        if (node == null) return 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 + Stream.of(leftGain, rightGain).mapToInt(Integer::intValue).max().orElse(0);
    }
}

解释

方法:

这个方法利用深度优先搜索(DFS)遍历二叉树的每个节点,同时计算以每个节点为顶点的最大路径和。对于每个节点,考虑两种情况:1.路径包括该节点及其左右子树;2.路径不包括子树,只有该节点自己。具体算法中,首先计算左右子树提供的最大贡献值,如果子树的贡献值为负,则认为不包括该子树的贡献。然后,更新全局的最大路径和,包括当前节点值以及左右子树的最大贡献。此外,函数返回到父节点的最大单边路径和,以便父节点计算其最大路径和时使用。这种方法确保我们计算了所有可能的路径,并在遍历过程中保存了最大值。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在更新全局最大路径和时考虑了左右子树的贡献值与当前节点值之和,而返回到父节点的路径和时只考虑了其中的最大单边路径和加当前节点值?
在计算全局最大路径和时,考虑的是通过当前节点连接左右子树形成的完整路径,这可能包括左子树、当前节点、右子树。这种情况下,路径是不可能延伸到当前节点的父节点,因为这将形成一个分叉(非线性路径)。因此,当考虑到达父节点的最大路径时,我们只能选择左子树和右子树中的一个较大贡献加上当前节点的值,这样确保路径是连续的且没有分叉,适合向上延伸至树的其他部分。
🦆
如果节点的值为负数,会如何影响算法计算左右子树的贡献值和最终的最大路径和?
如果节点的值为负数,它会减少从该节点延伸出的路径的总和。在计算该节点的最大贡献值时,如果左子树或右子树的贡献值加上当前节点的负值仍然小于零,那么这个贡献值不应被包括在内,因为它会减少到达该节点的父节点的最大路径和。在实际的dfs实现中,我们通过返回`max(max(left, right) + node.val, 0)`确保了贡献值为负时,不会影响到父节点的路径和。这意味着,即使当前节点的值为负,也只有当节点的贡献值能够提供正增益时才考虑这种贡献。
🦆
在函数中使用了非局部变量`ans`进行全局最大路径和的更新,这种方式与传递参数相比有什么优缺点?
使用非局部变量`ans`可以使代码更加简洁,因为它允许在递归函数内直接更新全局最大路径和,而无需通过每个递归调用传递和返回这个值。这种方法的优点是减少了函数参数的复杂性,使得递归结构更清晰。然而,这也意味着函数的纯粹性(不依赖于外部状态)被破坏,这可能在多线程环境中引发问题,或者在需要多次调用同一函数但期望独立结果的情况下引起状态污染。此外,使用非局部变量使得函数的重用和测试变得更加困难。

相关问题