BM38-在二叉树中找到两个节点的最近公共祖先

题目

给定一棵二叉树(保证非空)以及这棵树上的两个节点对应的val值 o1 和 o2,请找到 o1 和 o2 的最近公共祖先节点。

数据范围:树上节点数满足 1≤n≤10^5  , 节点值val满足区间 [0,n)

要求:时间复杂度 O(n)

注:本题保证二叉树中每个节点的val值均不相同。

如当输入{3,5,1,6,2,0,8,#,#,7,4},5,1时,二叉树{3,5,1,6,2,0,8,#,#,7,4}如下图所示:

所以节点值为5和节点值为1的节点的最近公共祖先节点的节点值为3,所以对应的输出为3。

节点本身可以视为自己的祖先。

示例1

输入:{3,5,1,6,2,0,8,#,#,7,4},5,1

返回值:3

示例2

输入:{3,5,1,6,2,0,8,#,#,7,4},2,7

返回值:2


思路1:非递归写法

要想找到两个节点的最近公共祖先节点,可以从两个节点往上找,每个节点都往上走,一直走到根节点,那么根节点到这两个节点的连线肯定有相交的地方,如果是从上往下走,那么最后一次相交的节点就是他们的最近公共祖先节点。

  1. 层序遍历二叉树(BFS),记录遍历到的每个节点的父节点,存储在Map中,当两个节点o1,o2都遍历到为止。
  2. 从o1节点开始一直到根节点,记录o1节点和它的祖先节点的值,存入ancestors中。
  3. 查看o1节点和它的祖先节点是否包含o2节点,如果不包含再看是否包含o2节点的父节点......
  4. 第一次包含的节点,即是o1和o2的公共祖先节点。

代码1

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     *
     * @param root TreeNode类
     * @param o1 int整型
     * @param o2 int整型
     * @return int整型
     */
    public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
        //记录遍历到的每个节点的父节点存入Map中
        Map<Integer, Integer> parent = new HashMap<>();
        //队列作为辅助
        Queue<TreeNode> queue = new LinkedList<>();
        //先将根节点存入Map和queue中
        parent.put(root.val, Integer.MIN_VALUE); //根节点没有父节点,给它默认一个值
        queue.add(root);

        //直到两个节点都找到为止
        while (!parent.containsKey(o1) || !parent.containsKey(o2)) {
            //队列是一边进一边出,这里poll方法是出队
            TreeNode node = queue.poll();
            if (node.left != null) {
                //左子节点不为空,记录下它的父节点
                parent.put(node.left.val, node.val);
                //左子节点不为空,把它加入到队列中
                queue.add(node.left);
            }
            //右节点同上
            if (node.right != null) {
                parent.put(node.right.val, node.val);
                queue.add(node.right);
            }
        }

        Set<Integer> ancestors = new HashSet<>();
        //记录下o1和它的祖先节点,从o1节点开始一直到根节点
        while (parent.containsKey(o1)) {
            ancestors.add(o1);
            o1 = parent.get(o1);
        }
        //查看o1和它的祖先节点是否包含o2节点,如果不包含再看是否包含o2的父节点……
        while (!ancestors.contains(o2)) {
            o2 = parent.get(o2);
        }
        //最先相交的节点即是o1和o2的最近公共祖先节点
        return o2;
    }
}
  • 时间复杂度:O(n),n是二叉树节点的个数,最坏情况下每个节点都会被访问一遍。
  • 空间复杂度:O(n),一个是BFS需要的队列,一个是父子节点关系的map。

思路2:递归写法​​​​​​​


代码2

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     *
     * @param root TreeNode类
     * @param o1 int整型
     * @param o2 int整型
     * @return int整型
     */
    public int lowestCommonAncestor(TreeNode root, int o1, int o2) {
        return helper(root, o1, o2).val;
    }

    public TreeNode helper(TreeNode root, int o1, int o2) {
        if (root == null || root.val == o1 || root.val == o2) {
            return root;
        }

        TreeNode left = helper(root.left, o1, o2);
        TreeNode right = helper(root.right, o1, o2);

        //如果left为空,说明这两个节点在root结点的右子树上,只需要返回右子树查找的结果即可
        if (left == null) {
            return right;
        }
        //同上
        if (right == null) {
            return left;
        }
        
        //如果left和right都不为空,说明这两个节点一个在root的左子树上,一个在root的右子树上,只需要返回cur结点即可。
        return root;
    }
}
  • 时间复杂度:O(n),n是二叉树节点的个数,最坏情况下每个节点都会被访问一遍。
  • 空间复杂度:O(n),因为是递归,取决于栈的深度,最差最差情况下,二叉树退化成链表,栈的深度是n。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值