算法 – 如何找到任何二叉树中的两个节点的最低共同祖先?

这里的二叉树可能不一定是二叉搜索树。
该结构可以被认为是 –

struct node {
    int data;
    struct node *left;
    struct node *right;
};

我可以与朋友一起工作的最大解决方案是这样的 –
考虑this binary tree

顺序遍历得到 – 8,4,9,2,5,1,6,3,7

后序遍历得到 – 8,9,4,5,2,6,7,3,1

因此,例如,如果我们想找到节点8和5的共同祖先,则在有序树遍历中列出所有在8和5之间的节点,在这种情况下恰好是[4,9 ,2]。然后我们检查这个列表中的哪个节点最后出现在后序遍历中,这是2.因此8和5的共同祖先是2。

这种算法的复杂性,我相信是O(n)(O(n)for inorder /后序遍历,剩下的步骤再次是O(n),因为它们只是数组中的简单迭代)。但是有很大的机会,这是错误的。 🙂

但这是一个非常粗糙的方法,我不知道如果它崩溃了一些情况。这个问题有没有其他(可能更优化)解决方案?

最佳答案
Nick约翰逊是正确的,如果没有父指针,一个O(n)时间复杂度算法是你能做的最好的。)对于该算法的简单递归版本,请参阅在O(n)时间运行的Kinding’s post代码。

但请记住,如果你的节点有父指针,一个改进的算法是可能的。对于所讨论的两个节点,从节点开始构造一个包含从根到节点的路径的列表,并且前面插入父节点。

所以对于你的例子中的8,你得到(显示步骤):{4},{2,4},{1,2,4}

对您的其他节点执行相同的操作,导致(步骤未显示):{1,2}

现在比较你创建的两个列表,查找列表不同的第一个元素,或者其中一个列表的最后一个元素,以先到为准。

该算法需要O(h)时间,其中h是树的高度。在最坏的情况下,O(h)等价于O(n),但是如果树是平衡的,那就是O(log(n))。它还需要O(h)空间。可以使用仅使用恒定空间的改进版本,代码显示在CEGRD’s post

无论树是如何构造的,如果这将是一个操作,你在树上执行多次,而不改变它之间,还有其他算法,你可以使用需要O(n)[线性]时间准备,但后来找到任何对只需要O(1)[constant]时间。对于这些算法的参考,请参见最低的共同祖先问题页面在Wikipedia.(感谢Jason最初发布此链接)

转载注明原文:算法 – 如何找到任何二叉树中的两个节点的最低共同祖先? - 代码日志