二叉树:找出两个节点的最近公共祖先

本文介绍了一种求解二叉树中两个指定节点最近公共祖先(LCA)的方法。通过递归前序遍历的方式,当左右子树分别包含两个节点时,当前节点即为LCA。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述

给定二叉树(不是二叉搜索树)和两个节点 p 和 q,编程实现找到二者的最近公共祖先(Lowest Common Ancestor,LCA)。

二、思路分析

LCA(Least Common Ancestor):【最近公共祖先】两个节点所有公共祖先中离根节点最远的节点。从根开始遍历树,如果任意给定节点(p和q)与根匹配,则根为 LCA。如果根与任何节点都不匹配,重复左右子树中寻找节点 p 和 q。如果在其左子树中存在一个节点而在右子树中存在的另一个节点,则此节点即为 LCA。如果两个节点都位于左子树中,则 LCA 也位于左子树中,否则 LCA 位于右子树中。由此,找到该树中两个指定节点的最近公共祖先,有三种情况,如图:

树中从 p 节点到 q 节点的距离:从根到 p 的距离加上从根到 q 的距离,减去从根到它们最近共同祖先的距离的两倍。

三、代码实现

//下面使用的遍历方法为前序遍历
public class Lca {
    // 1、构造二叉树
    public Node buildTree() {
        Node A = new Node('A');
        Node B = new Node('B');
        Node C = new Node('C');
        Node D = new Node('D');
        Node E = new Node('E');
        Node F = new Node('F');
        Node G = new Node('G');
        Node H = new Node('H');
        //这里是构造二叉树的关键
        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;
        E.right = H;
        return A;
    }

    //找两个结点最近的公共祖先
    public Node lowstCommonAncestor(Node root, Node p, Node q) {
        if (root == null) {
            return null;
        }
        if (root == p || root == q) {
            return root;
        }
        Node left = lowstCommonAncestor(root.left, p, q);
        Node right = lowstCommonAncestor(root.right, p, q);
        if (left != null && right != null) {
            return root;
        } else if (left != null) {
            return left;
        } else {
            return right;
        }
    }

    public static void main(String[] args) {
        Lca binaryTree = new Lca();
        Node root = binaryTree.buildTree();
        System.out.println(root);//这个是根即A的地址:com.xxp.common.algorithms.Node@5f4da5c3
        //这里打印出的是地址,可推断该公共祖先是A。与上面比较会发现是一致的
        System.out.println("找两个结点最近的公共祖先:" + binaryTree.lowstCommonAncestor(root, root.left, root.right.left));
        System.out.println(binaryTree.lowstCommonAncestor(root, root.left, root.right.left).val);
        System.out.println(root.val);

    }
}

class Node {
    public char val;
    public Node left;//左孩子
    public Node right;//右孩子

    public Node(char val) {
        this.val = val;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值