繁体   English   中英

使用递归的二叉树中的最低共同祖先

[英]Lowest Common Ancestor in Binary Tree using recursion

我正在尝试通过自上而下的递归来解决二叉树的最低公共祖先(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 上相关问题的答案中推荐的内容。
现在,如果我们假设树的所有节点都具有唯一值,则此代码运行良好。 换句话说,这种方法似乎在重复的情况下会中断(或者,它只是我的实现?)

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

这是确切的实现:

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)))

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

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

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

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

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

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

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

代码将如下所示

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

这个想法是这样的:我们在根的左右子树中递归搜索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;
        }
    }
}
var lowestCommonAncestor = function(root, p, q) { 
   
    const lca = (root) => {
        // Check if the root is the value, is yes then just return the root
        if (!root || root.val === p.val || root.val === q.val){
            return root;
        }

        // Traverse through left and right tree
        let L = lca(root.left);
        let R = lca(root.right);

        // If we have left and right node, which means val1 and val2 are on the either side of root,
        // then return root else return L or R
        if (L && R)
            return root;
        return L ? L : R;
    }
    return lca(root) || -1;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM