二叉树的最近公共祖先
难度 中等 题目链接
题目说明:
从上图可以发现,公共祖先的结论:一个在我左边,一个在我右边。我就是公共祖先。还有一个特殊情况:
如果有一个是另一个的祖先,那么自己就是公共祖先。
方法一
首先,我们需要写一个函数来判断p和q是否在树中:
我们需要判断根是不是其中的p或者q。如果不是我们要去判断在不在的左子树和右子树的一个情况。
然后对pInLeft,pInRight,qInRight,qInLeft进行判断分析。
如果在同一边,我们就递归到一边去找。
完整代码:
但是这样的写法,它的时间复杂度不是特别好。
如果是这样的二叉树,那么它第一次N,第二次是N-1,第三次是N-2,… …所以时间复杂度是O(N^2),它由于会递归N次,所以空间复杂度是O(N)。
方法二
利用栈来记录p和q结点到root结点的路径,然后转换成相交问题。
首先,先让结点入栈,然后判断此结点是否是q。不是,我们先递归左子树。
还是同样的道理,先把5入进去再判断。不能先判断,原因如果不是结点5不入进去就找不到下面的结点了。
当来到6的时候,6不是q,左子树为空,返回。递归到右子树,右子树为空,返回。说明6不是q结点路径上的一员,所以6要出栈。
那么5的左子树就递归完了,开始走5的右子树。
来到7的时候和6的时候一样,左子树,右子树都为空,7也不是q,所以7出栈。2的左子树递归结束没找到,去2的右子树找。
q找到了,那么就可以返回true了。此时栈里的数据就是路径。
此时,两个栈中都存放了自己的路径。
我们就可以转换成相交的问题。让长的先pop掉差距,然后比较相等的结点。
方法三
方法三我们用递归套路来做,首先我们分析可能性:假设一个结点为x,我们要找p,q结点的最近公共祖先。
第一种情况:x不是最近公共祖先。
1. 最近公共祖先在x的左子树或者右子树。
2. p,q不在以x为根结点的树中。
第二种情况:x是最近公共祖先。
1. x是p或q中的一个。
2. p,q其中一个在左子树,另外一个在右子树。
分析可能性之后,我们就可以列信息体了。
根据情况的分析,我们需要:
1.p,q是否在以x为根结点的树中。
2.最近公共祖先是否在以x为根结点的树中。
然后写为空和不为空的情况:
当递归回来的时候,我们需要写自己的信息:
最后返回结果:
方法四
方法四我们可以使用容器来做。
解决思路:
1.定义一个map一个存当前结点,一个存当前结点的父结点。
然后将根结点和它的父结点存到map中。
2.写一个前序遍历把整棵树的孩子结点和父结点相对应。
3.定义一个set把p存进去,然后把p的所有祖先都存进去。
4.在set里面去找q,如果没找到就在map里找它的父结点,一直在set找到,此时结点就是最近公共祖先。
代码实现: