Java 不了解二叉树最大路径和问题的解决方案

Java 不了解二叉树最大路径和问题的解决方案,java,algorithm,binary-tree,Java,Algorithm,Binary Tree,Geeksforgeks网站为二叉树的最大路径和问题提供了解决方案。问题如下: int findMaxUtil(Node node, Res res) { if (node == null) return 0; // l and r store maximum path sum going through left and // right child of root respectively int l = findMax

Geeksforgeks网站为二叉树的最大路径和问题提供了解决方案。问题如下:

int findMaxUtil(Node node, Res res) 
{ 
  
    if (node == null) 
        return 0; 
  
    // l and r store maximum path sum going through left and 
    // right child of root respectively 
    int l = findMaxUtil(node.left, res); 
    int r = findMaxUtil(node.right, res); 
  
    // Max path for parent call of root. This path must 
    // include at-most one child of root 
    int max_single = Math.max(Math.max(l, r) + node.data, 
                              node.data); 
  
  
    // Max Top represents the sum when the Node under 
    // consideration is the root of the maxsum path and no 
    // ancestors of root are there in max sum path 
    int max_top = Math.max(max_single, l + r + node.data); 
  
    // Store the Maximum Result. 
    res.val = Math.max(res.val, max_top); 
  
    return max_single; 
} 

int findMaxSum() { 
    return findMaxSum(root); 
 } 
  
// Returns maximum path sum in tree with given root 
int findMaxSum(Node node) { 
  
    // Initialize result 
    // int res2 = Integer.MIN_VALUE; 
    Res res = new Res(); 
    res.val = Integer.MIN_VALUE; 
  
    // Compute and return result 
    findMaxUtil(node, res); 
    return res.val; 
} 
给定一棵二叉树,求最大路径和。路径可以开始和结束 在树中的任意节点结束

解决方案的核心如下:

int findMaxUtil(Node node, Res res) 
{ 
  
    if (node == null) 
        return 0; 
  
    // l and r store maximum path sum going through left and 
    // right child of root respectively 
    int l = findMaxUtil(node.left, res); 
    int r = findMaxUtil(node.right, res); 
  
    // Max path for parent call of root. This path must 
    // include at-most one child of root 
    int max_single = Math.max(Math.max(l, r) + node.data, 
                              node.data); 
  
  
    // Max Top represents the sum when the Node under 
    // consideration is the root of the maxsum path and no 
    // ancestors of root are there in max sum path 
    int max_top = Math.max(max_single, l + r + node.data); 
  
    // Store the Maximum Result. 
    res.val = Math.max(res.val, max_top); 
  
    return max_single; 
} 

int findMaxSum() { 
    return findMaxSum(root); 
 } 
  
// Returns maximum path sum in tree with given root 
int findMaxSum(Node node) { 
  
    // Initialize result 
    // int res2 = Integer.MIN_VALUE; 
    Res res = new Res(); 
    res.val = Integer.MIN_VALUE; 
  
    // Compute and return result 
    findMaxUtil(node, res); 
    return res.val; 
} 
Res
具有以下定义:

 class Res { 
    public int val; 
}
我对这些代码背后的推理感到困惑:

int max_single = Math.max(Math.max(l, r) + node.data, node.data);  

int max_top = Math.max(max_single, l + r + node.data); 

res.val = Math.max(res.val, max_top); 

return max_single; 
我相信上面的代码遵循这个逻辑,但我不理解为什么这个逻辑是正确的或有效的:

对于每个节点,最大路径可以通过四种方式 节点:

  • 仅节点
  • 通过左子节点+节点的最大路径
  • 通过右子节点+节点的最大路径
  • 通过左子节点的最大路径+节点+通过右子节点的最大路径
  • 特别是,我不理解当变量
    res.val
    包含我们感兴趣的答案时,为什么在函数
    findMaxUtil
    中返回
    max\u single
    。网站上给出了以下原因,但我不理解:

    需要注意的一点是,每个子树的根都需要返回 最大路径和,最多涉及根的一个子级


    有人能解释一下解决方案的这一步吗?

    您缺少
    res.val
    的值。该算法试图探索整个树,使用的
    res.val
    等于在此之前探索的最大路径长度。在每个步骤中,它递归地遍历子级,并使用最大路径长度更新
    res.val
    ,如果该路径长度高于已经存在的路径长度

    证明:

    假设您的算法适用于高度
    n
    的树。对于高度
    n+1的树,有一个根和两个子树的高度
    n
    。同时考虑<代码> FIDMAXUTIL对于 特别是,我不理解为什么当变量res.val包含我们感兴趣的答案时,函数findMaxUtil中返回max_single

    问题在于
    findMaxUtil()
    实际上做了两件事:它返回应用它的树的最大和,并更新一个变量,该变量跟踪遇到的最大和。原始代码中有这样一条注释,但您在问题中删去了它,可能是为了简洁:

    // This function returns overall maximum path sum in 'res' 
    // And returns max path sum going through root. 
    int findMaxUtil(Node node, Res res) 
    
    因为,很容易忽略这样一个事实,即在
    Res
    参数中传递的
    Res
    可以通过此函数进行更改。这正是你所问的那句台词中发生的事情:

    int max_single = Math.max(Math.max(l, r) + node.data, node.data);  
    
    int max_top = Math.max(max_single, l + r + node.data); 
    
    res.val = Math.max(res.val, max_top); 
    
    return max_single;
    
    第一行查找节点本身的最大值或节点加上最大子树,结果是经过根的路径和的最大值。在最后一行返回该值是该函数所做的一件事。第二行和第三行查看该值,并考虑它是否包含两个孩子的路径大于任何先前看到的路径,如果是,则更新<代码> RES ,这是该函数的另一个功能。请记住,
    res
    是存在于方法之外的某个对象,因此对它的更改将一直持续到递归停止,并且启动整个过程的
    findMaxSum(Node)
    将返回
    res.val


    因此,回到顶部的问题,
    findMaxUtil
    返回
    max\u single
    的原因是它使用该值递归地确定通过每个子树的最大路径。
    res
    中的值也会更新,以便
    findMaxSum(Node)
    可以使用它。

    老实说,我认为该网站上的描述非常不清楚。我会尽我所能让你相信算法背后的道理

    我们有一个二叉树,节点上有值:

    我们在树中寻找一条路径,一条连接节点链

    由于它是一个有向树,任何非空路径都由一个最低深度节点(即路径中最接近树根的节点)、一个从最低深度节点左侧下降的零个或多个节点的路径以及从最低深度节点右侧下降的零个或多个节点的路径组成。特别是,在树的某个地方有一个节点,它是最大路径中深度最低的节点。(事实上,可能有不止一条这样的路径被绑定为相等的值,它们可能都有各自不同的最低深度节点。这很好。只要至少有一条,这就是问题所在。)

    (我在图中使用了“highest”,但我的意思是“lowest depth”。更清楚地说,每当我使用“depth”或“downing”时,我指的是树中的位置。每当我使用“maximum”时,我指的是一个节点的值或路径中节点的值之和。)

    因此,如果我们能找到它的最低深度节点,我们知道最大值路径由节点本身、从(包括)其左子节点向下的零个或多个节点的子路径以及从(包括)其右子节点向下的零个或多个节点的子路径组成。这是一小步,可以得出这样的结论:左侧和右侧的下降路径必须是最大值,例如每侧的下降路径。(如果这不是显而易见的,考虑到你选择的其他路径,你可以通过选择那个边上的最大值下降路径来增加总价值。)如果这些路径中的任一个或两个路径都有负值,那么我们只在负侧上不包含任何节点。 所以我们有一个单独的子问题-给定一个子树,通过它的根下降的最大值路径的值是多少?如果所有根在其子路径上的路径都有负和,或者没有子路径,那么它可能就是根本身。否则,它是根加上在其子级上根的任何一个的最大值下降路径。这是