最近公共祖先问题
题目:
LeetCode236,给定一个二叉树,找到该树中的两个指定结点的最近公共祖先,
最近公共祖先的定义为:“对于有根树T的两个节点p、q,最近公共祖先表示为一个节点x,满足x是p、q的祖先,且x的深度尽可能大(一个节点也可以是它自己的祖先)。
给出以下示例:
要想找到两个节点的最近公共祖先节点,我们可以从两个节点往上找,每个节点都往上走,一直走到根节点,根节点到这两个节点的连线肯定有相交的地方,那么相交的地方就是最近的公共祖先节点,看图:
思路:
6的祖先结点有 3和5,7的是3,5,2,所以6和7的最近公共祖先是5。用代码实现我们需要考虑好几种情况,根据以上定义,若root是p,q的最近公共祖先,是以下情况之一:
- p和q在root的子树中,且位于root的两侧(即分别在左右子树中);
- p = root,且q在root的左或者右子树中;
- q = root,且p在root的左或者右子树中;
在具体的执行中,我们要判断的情况回复杂一些:
我们在上面的树中查找6和7的公共祖先,遍历的逐步向下,假如某个时刻访问的结点为root,我们通过后序递归的查找其左右子树是否存在6或者7,则此时的判断逻辑是:
- 1.如果得到left和right都为null,说明在该子树root里p和q一个都没找到,直接返回null即可。例如上图中递归到了root为1的子树时。
- 2.如果right和left都不为null,说明p和q分别在root的两侧,例如root为5时,此时6和7就分别在其两侧,直接返回5即可。如果不在其中就会返回null。
- 3.当right为空,left不为空时,需要考虑两种情况:
- 先判断root是不是p或者q,如果时说明p和q一个是另一个的祖先,直接返回就好,
- 说明right子树里面什么也没查到,而是6和7在left子树里面,此时需要递归的去查左子树即可,就要继续递归判断。例如root为3时,此时递归的结果必然是right为null而left不为空。
还有最后一种情况和第3种的相反:left为空而right不为空,此时与情况3相反的情况。
总结递归的代码:
public TreeNode lowest(TreeNode root,TreeNode p,TreeNode q){
//1. 判断根节点为空和root是不是p或q的情况,
if (root == null || root == p || root == q) return root;
//2. 在左右子树递归
//左子树的放回结果,
TreeNode left = lowest(root.left, p, q);
//右子树的返回结果
TreeNode right = lowest(root.right, p, q);
//得到返回的结果,进行前两种判断
//q和p不存在的情况 1.
if (left == null && right == null)return null;
//p和q在同侧
if (left == null) return right;//3
if (right == null) return left;//4
return root; //2.if(left != null && right != null)
}