【问题标题】:Lowest Common Ancestor in Binary Tree using recursion使用递归的二叉树中的最低共同祖先
【发布时间】:2018-03-09 05:27:14
【问题描述】:

我正在尝试通过自上而下的递归来解决二叉树的最低公共祖先(LCA)问题。

我使用的方法是:

想法:在任一子树中找到具有所需节点之一的节点,而另一个所需节点是相反的子树。

PSEUDOCODE
1. If the value of root is equal to either of the desired node's value, 
   the root is the LCA.
2. Search in the left subtree for either node.
3. Search in the right subtree for either node.
4. If neither of them contains any of the two nodes,
   the nodes do not exist in the tree rooted at the root node.
5. If each of them contains one node,
   the root is the LCA.
6. If either one of them contains a node,
   return it to the root.

这也是 StackOverflow 上 related questions 的答案中推荐的内容。
现在,如果我们假设树的所有节点都具有唯一值,则此代码运行良好。换句话说,这种方法似乎在重复的情况下会失效(或者,它只是我的实现吗?)

我想知道如何修复我的代码以使用重复值。如果这种方法不能产生最佳解决方案,我应该如何改变我的方法?

下面是具体实现:

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

    def __repr__(self):
        return 'TreeNode({}, {}, {})'.format(self.val, self.left, self.right)

def lowestCommonAncestor(root, p, q):
    """
    :type root: TreeNode
    :type p: TreeNode
    :type q: TreeNode
    :rtype: TreeNode
    """
    if root is None:
        return None

    if p.val == root.val or q.val == root.val:
        return root

    left_subtree = lowestCommonAncestor(root.left, p, q)
    right_subtree = lowestCommonAncestor(root.right, p, q)

    if left_subtree is None and right_subtree is None:
        return None

    if left_subtree is not None and right_subtree is not None:
        return root

    if left_subtree is None:
        return right_subtree
    else:
        return left_subtree

例如:

root = TreeNode(2)
root.left = TreeNode(3)
root.left.left = TreeNode(1)
root.right = TreeNode(5)
root.right.left = TreeNode(7)
root.right.right = TreeNode(1)
print(lowestCommonAncestor(root, TreeNode(1), TreeNode(7)))

这将返回树的根作为结果。 结果 = TreeNode(2)

毫无疑问,根始终是祖先。
但是,存在比根“更低”的共同祖先 - TreeNode(5)

【问题讨论】:

    标签: python algorithm recursion tree


    【解决方案1】:

    思路是这样的:我们在root的左右子树中递归搜索p和q。如果左子树的结果为空,则意味着 p 和 q 不在根的左侧,因此我们可以安全地得出结论,LCA 必须位于根的右子树中。如果右子树的结果为空,类似的结论也成立。但是,如果它们都不为空,则表明 p 和 q 在根的任一侧。因此,根是 LCA。

    class Solution {
        public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
            if (root == null) {
                return root;
            }
    
            if (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;
            } else if (left != null) {
                return left;
            } else {
                return right;
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      代码如下所示

      def lowestCommonAncestor(root, p, q):
      """
      :type root: TreeNode
      :type p: TreeNode
      :type q: TreeNode
      :rtype: TreeNode
      """
      flag=0
      if root is None:
          return None
      
      if p.val == root.val or q.val == root.val:
          flag=1
          #return root
      
      left_subtree = lowestCommonAncestor(root.left, p, q)
      right_subtree = lowestCommonAncestor(root.right, p, q)
      
      if left_subtree is None and right_subtree is None:
          if flag==0:
              return None
          else:
              return root
      
      if left_subtree is not None and right_subtree is not None:
          return root
      
      if left_subtree is None:
          if flag==1:
              if (right_subtree.value!=p && right_subtree.value!=q) || right_subtree.value==root.value:
                  return right_subtree
              elif right_subtree.value!=root.value:
                  return root
          else:
              return right_subtree
      else:
          if flag==1:
              if (left_subtree.value!=p && left_subtree.value!=q) || left_subtree.value==root.value:
                  return left_subtree
              elif left_subtree.value!=root.value:
                  return root
          else:
              return left_subtree
      

      【讨论】:

        【解决方案3】:

        你有一些问题: 1) 你为什么要检查 Node.val?您应该能够直接将一个节点与另一个节点进行比较。当您有一棵具有多个具有相同值的节点的树时,这应该可以解决问题......假设这是您唯一的问题。

        2) 如果左子树非空且右子树非空,为什么要返回 root?当然,在许多情况下,这将返回 root。这通常不是我们想要的行为。

        您可能想从头开始重新考虑您的算法(您有一些不错的想法,但现在您发现自己犯了一些错误,而且由于这个问题相当简单/直截了当,重新思考可能更有益) .

        一个建议:由于这个问题是关于树的问题,并且与搜索/路径有关,因此考虑寻找从节点 p 到节点 q 的路径的问题。我们知道,在一棵树中,任何两个节点都存在一条路径(这仅仅是因为树是一个连通的无环图,根据定义)。

        在递归到基本情况后返回时,您可能会牢记这个想法,或者在递归到基本情况后,您可能想要创建一个数据结构来将访问过的节点存储在循环中,然后测试一些条件并可能递归更多(本质上是 DFS 方法与 BFS 方法,而 BFS 方法使用显式记忆/添加内存,而 DFS 使用堆栈来记忆事物)。

        【讨论】:

        • 我怎样才能将一个节点与另一个节点进行比较,即在__eq__ 和相关的比较魔术方法中应该实现什么逻辑?此外,在这种情况下,我使用的是在线法官的数据结构,我无法修改。
        • 每个节点都有自己的内存块id。在 python 中使用id() 获取它。这些字符串是唯一的,可用于比较。
        猜你喜欢
        • 2011-07-28
        • 2012-11-08
        • 2020-08-16
        • 1970-01-01
        • 2021-12-09
        • 2017-04-04
        • 2012-01-16
        • 1970-01-01
        • 2017-02-21
        相关资源
        最近更新 更多