二叉树LCA--leetcode236题

二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3

1.哈希表解法
(1)创建队列queue进行二叉树层序遍历
(2)设置map映射父子结点关系,从而可以从子结点访问到父节点
(3)利用map记录的联系找出p所有的祖宗结点存在set
(4)遍历q的父节点,如果存在于set中,则为最近公共祖先,直接返回

var lowestCommonAncestor = function (root, p, q) {
    /* 如果root为p或q直接返回 */
    if (!root || root === p || root === q) return root;
    let queue = [root];
    let map = new WeakMap();
    /* 遍历二叉树,存映射关系 */
    while (queue.length) {
        let size = queue.length;
        while (size--) {
            let front = queue.shift();/* 队首 */
            if (front.left) {
                queue.push(front.left);
                map.set(front.left, front);
            }
            if (front.right) {
                queue.push(front.right);
                map.set(front.right, front);
            }
        }
    }
    /* 记录p的所有祖先 */
    let acts = new Set();
    while (p) {
        acts.add(p);//放到set中
        p = map.get(p);//父结点
    }
    /* 查找公共祖先 */
    while (q) {
        if (acts.has(q)) return q;
        q = map.get(q);
    }
};

2.深度优先搜索解法
原理:根据p,q是否分别在两侧子树判断LCA
(1)深度优先遍历二叉树,如果当前节点为 p 或者 q,直接返回这个节点,
(2)不符合以上条件,查看左右孩子,左孩子中不包含 pq 则去找右孩子,右孩子不包含 p 或者 q 就去找左孩子
(3)左右孩子中都存在 p 或者 q, 那么这个节点就是LCA(只有对于最近公共祖先p,q才会在不同侧)

var lowestCommonAncestor = function (root, p, q) {
    /* root为null,p,q这三种情况时返回 */
    if (!root || root === p || root === q) return root;
    /* 查找左子树 */
    let left = lowestCommonAncestor(root.left, p, q);
    /* 查找右子树 */
    let right = lowestCommonAncestor(root.right, p, q);
    /* 左子树不存在p/q */
    if (!left) return right;
    else if (!right) return left;
    else return root;//左右子树各存在p,q中的一个,为公共祖先
};

补充

对于二叉搜索树,还可以进行优化,通过权值大小比对可以确定p,q相对root的位置,如果p,q分别在root的两侧,则root就是最近公共祖先。
题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/submissions/
递归法:

var lowestCommonAncestor = function (root, p, q) {
    if (!root || root === p || root === q) return root;
    /* 判断p,q在root的哪边,如果一左一右则root就是最近公共祖先 */
    if (root.val > p.val && root.val > q.val) {
        return lowestCommonAncestor(root.left, p, q);
    }
    else if (root.val < p.val && root.val < q.val) {
        return lowestCommonAncestor(root.right, p, q);
    }
    else {
        return root;
    }
};

非递归:

var lowestCommonAncestor = function (root, p, q) {
    if (!root || root === p || root === q) return root;
    while (root) {
        if (root.val > p.val && root.val > q.val) {
            root = root.left;
        } else if (root.val < p.val && root.val < q.val) {
            root = root.right;
        } else {
            return root;
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值