【问题标题】:How to implement lowest common ancestor for a binary tree using Java?如何使用Java实现二叉树的最低共同祖先?
【发布时间】:2017-04-04 10:12:44
【问题描述】:

我遇到了以下实现,花了一些时间,但仍然无法掌握想法。有人可以逐行解释它在做什么吗?我只是不明白它在什么时候可以决定一个节点是一个祖先。

谢谢

public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q)  return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left != null && right != null)   return root;
        return left != null ? left : right;
    }
}

【问题讨论】:

  • 递归函数真的很难理解。把它们画在纸上会有帮助。
  • 这里的代码是这个答案中代码的稍微紧凑的版本:stackoverflow.com/a/9046307/2513200
  • @Hulk 没有冒犯,区别完全无关紧要,即使从编译器的角度来看也是如此。
  • @SauravSahu 是的,我同意它是等价的。区别纯粹是样式和 cmets。

标签: java algorithm binary-tree lowest-common-ancestor


【解决方案1】:

在树枝中标记数字存在的基本思想是使用 non-null 指针来表示数字 FOUNDnull NOTFOUND 的指针。

一旦找到一个数字(pq),或者当rootnull 时,调用堆栈就会回滚。后面的一个明确指出没有搜索到的号码。

有四种可能的情况:

1.) 都在一个父母之下。

                      root
                      /  \ 
            Leftsubtree  Rightsubtree
                p/q        q/p

在这种情况下,在下面的代码中,会满足 if(left != null && right != null) return root;

2.) 一个父母。

      q/p                     p/q
      /            OR          \ 
Leftsubtree                 Rightsubtree
  p/q                           q/p

在这种情况下,这将满足if(root == null || root == p || root == q) return root;

3.) 它们中的任何一个都不存在于树中。 这种情况会未被检测到。如案例 #2 所示,该函数立即返回,无需进一步遍历并在其下方的树中查找其对应项。

4.) 它们都不存在于树中。

第一行if(root == null ... return ; 将为每个不存在的孩子执行。最终结果将是 null 返回,因为找不到任何数字。


逐行代码说明。

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if(root == null || root == p || root == q)  return root;

    /* (root == null)  This proves that root is not in the branch of tree of our interest. Returning null would means NOTFOUND.*/
    /* (root == p || root == q) either p or q or both are found. Returning non-null root would means FOUND. */

    /*Check for presence in leftsubtree */
    TreeNode left = lowestCommonAncestor(root.left, p, q);

    /*Check for presence in rightsubtree */
    TreeNode right = lowestCommonAncestor(root.right, p, q);

    /*            root
                  /  \ 
        leftsubtree  Rightsubtree
            p/q        q/p

    */
    if(left != null && right != null)   return root; //both the numbers are found inside tree under root 

    // left or right subtree OR both don't have p or q. Return the overall find result under root.
    return left != null ? left : right;
}

【讨论】:

    【解决方案2】:
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // root == null (no root no LCA)
        // root == p || root == q (if either p or q is the root then root is LCA)
        if(root == null || root == p || root == q)  return root;
        //get the LCA of p and q in left sub tree
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        //get the LCA of p and q in right sub tree
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        // if one of p or q is in left subtree and another is in the right subtree, 
        //then the root is the LCA
        if(left != null && right != null)   return root;
        // if left is not null, left is LCA, else right is LCA 
        return left != null ? left : right;
    }
    
    【解决方案3】:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == NULL || root->val == p->val || root->val == q->val ||
            (p->val < root->val && root->val < q->val) ||
            (q->val < root->val && root->val < p->val)) {
            return root;
            }
        else if (root->val < p->val) return lowestCommonAncestor(root-> right, p, q);
        else return lowestCommonAncestor(root->left, p, q);
    

    这是我在 C++ 中的答案,但应该非常相似,只要将“->”切换为“。”句法。这是一个递归函数,它检查当前叶子及其左右子节点,一旦第一个 if 语句条件为真,这意味着它确定了最低的共同祖先,因为如果它的任何一个子节点更大,则意味着它是最小的价值。

    例如:给定 2 作为它的根,1 和 4 作为它的孩子(分别是左和右),1 低于 root,但 4 不是,所以 2 是最小公分母。 IT 将在第一次运行时停止。

    如果你自己画一棵二叉树并测试每一步,它会更有意义。

    【讨论】:

      【解决方案4】:
      if(root == null || root == p || root == q)  return root;
      

      如果当前root nodenull,那么在当前子树中不存在pqcommon ancestor,所以返回@ 987654324@

      如果 pq 等于 root。我假设 p=root,这里对于 q,它是 poffspringp 的 not offspring 然而哪种情况,不需要遍历p的子树,因为如果前一种情况pq 所以只返回 pp==root,否则直接返回 p,虽然在这种情况下 p 不会产生错误> 不是ancestor of q
      为声明
      if(left != null &amp;&amp; right != null) return root; 我稍后会解释。

          TreeNode left = lowestCommonAncestor(root.left, p, q);
          TreeNode right = lowestCommonAncestor(root.right, p, q);
      

      现在存在几种可能的情况:
      1. p 和 q 都是 root.left 的offspring
      2. p和q都是root.right的offspring
      3.这两个节点一个是root.left的offspring另一个是root.right的offspring


      这两个recursive statement用于查找p和qcommon ancestorfor 1,2else 用于查找 pqfor 3


      if(left != null && right != null)   return root;
      

      该语句用于处理3corresponding result,p和q存在root的left_subtree and right_suntree,所以ancestor root


       return left != null ? left : right;
      

      此语句用于处理1,2corresponding resultpq 存在相同的子树左侧或右侧。

      【讨论】:

      • 这是第一个直接针对please explain line by line what [this LCA implementation] is doing?的答案。它可以明确指出,对于“外部”使用,它假定 p 和_q_ 都位于root 的树中,而在“内部”/递归使用,它依赖于这并不总是如此,而不是lowestCommonAncestor()中的common。让指出问题中提出的“解决方案”缺少 doc cmets 以及 in-line cmets。
      猜你喜欢
      • 2011-07-28
      • 2012-11-08
      • 1970-01-01
      • 2018-03-09
      • 2012-01-16
      • 2020-08-16
      • 2017-02-21
      • 1970-01-01
      • 2021-12-09
      相关资源
      最近更新 更多