算法通关村第八关 | 寻找祖先问题

最近公共祖先问题

        题目:

LeetCode236,给定一个二叉树,找到该树中的两个指定结点的最近公共祖先,

        最近公共祖先的定义为:“对于有根树T的两个节点p、q,最近公共祖先表示为一个节点x,满足x是p、q的祖先,且x的深度尽可能大(一个节点也可以是它自己的祖先)。

给出以下示例:

算法通关村第八关 | 寻找祖先问题_第1张图片

         要想找到两个节点的最近公共祖先节点,我们可以从两个节点往上找,每个节点都往上走,一直走到根节点,根节点到这两个节点的连线肯定有相交的地方,那么相交的地方就是最近的公共祖先节点,看图:

算法通关村第八关 | 寻找祖先问题_第2张图片

思路:

        6的祖先结点有 3和5,7的是3,5,2,所以6和7的最近公共祖先是5。用代码实现我们需要考虑好几种情况,根据以上定义,若root是p,q的最近公共祖先,是以下情况之一:

  1. p和q在root的子树中,且位于root的两侧(即分别在左右子树中);
  2. p = root,且q在root的左或者右子树中;
  3. 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不为空时,需要考虑两种情况:
  1. 先判断root是不是p或者q,如果时说明p和q一个是另一个的祖先,直接返回就好,
  2. 说明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)
    }

你可能感兴趣的:(算法通关村专栏,算法)