题目是:输入两个树节点,求它们的最低公共祖先。
你要向面试官问的问题:
1.这棵树是不是二叉树?
如果是二叉树,并且是二叉搜索树,那么是可以找到公共节点的。查找方法:二叉搜索树是排序过的,位于左子树的节点都比父节点小,而位于右子树的节点都比父节点大,我们只需要从树的根节点开始和两个输入的节点进行比较。如果当前节点的值比两个节点的值都大,那么最低的共同父节点一定在当前节点的左子树中,于是下一步遍历当前节点的左子节点。如果当前节点的值比两个节点的值都小,那么最低的共同父节点一定在当前节点的右子树中,于是下一步遍历当前节点的右子节点。这样,在树中从上到下找到第一个在两个输入节点的值之间的节点就是最低的公共祖先。
2.把题目稍微换一下。如果这棵树不是二叉搜索树,甚至连二叉树都不是,而只是普通的树,又该怎么办呢?
此时需要询问:树的节点中有没有指向父节点的指针?
答:如果树中的每一个节点(除了根节点之外)都有一个指向父节点的指针,那么这个问题可以转换成求两个链表的第一个公共节点。假设树节点中指向父节点的指针是pParent,那么从树的每个叶节点开始都有一个由指针pParent串起来的链表,这些链表的尾指针都是树的根节点。输入两个节点,那么这两个节点位于两个链表上,它们的最低公共祖先刚好就是这两个链表的第一个公共节点。
3.再把题目的要求改变一下,现在假设这棵树是普通的树,而且树中的节点没有指向父节点的指针。
答:所谓两个节点的公共祖先,指的是这两个节点都出现在某个节点的子树中。我们可以从根节点开始遍历一棵树,每遍历到一个节点时,判断两个输入节点是不是在它的子树中。如果在子树中,则分别遍历它的所有子节点,并判断两个输入节点是不是在它们的子数中。这样从上到下一直找到的第一个节点,它自己的子树中同时包含两个输入的节点而它的子节点却没有,那么该节点就是最低的公共祖先。
举例说明:
假设还是输入节点F和H。我们先判断A的子树中是否同时包含节点F和H,得到的结果为true.接着我们再先后判断A的两个子节点B和C的子树是不是同时包含F和H,B的结果是true而C的结果是false.接下来我们再判断B的两个子节点D和E,发现这两个节点得到的结果是false.接下来我们再判断B的两个子节点D和E,发现这两个节点得到的结果都是false。于是B是最后一个公共祖先,即我们的输出。
这种思路会对同一个节点重复遍历很多次,你想想还有没有更快的算法?
问:可以用辅助内存吗? 如果可以的话,我的想法是用两个链表分别保存从根节点到输入的两个节点的路径,然后把问题转换成两个链表的最后公共节点。
具体说说: