Java 在二叉树中寻找最小公共祖先

Java 在二叉树中寻找最小公共祖先,java,algorithm,tree,binary-tree,Java,Algorithm,Tree,Binary Tree,可能重复: 我有一个二叉树,如下所示。我需要找到最不常见的祖先(LCA)。e、 g 6和4的LCA为1,4和5的LCA为2 1 / \ 2 3 / \ / \ 4 5 6 7 谁能建议我应该如何处理和解决这个问题 使用列表可以解决您的问题 您应该创建一个getAncestorList()。它按其祖先返回一个列表顺序,例如4有一个祖先列表[1,2],7有一个祖先列表[1,3] list1 = node1.getAncestorList() list2 = nod

可能重复:

我有一个二叉树,如下所示。我需要找到最不常见的祖先(LCA)。e、 g 6和4的LCA为1,4和5的LCA为2

    1
   / \
  2   3
 / \ / \
4  5 6  7 

谁能建议我应该如何处理和解决这个问题

使用列表可以解决您的问题

您应该创建一个getAncestorList()。它按其祖先返回一个列表顺序,例如4有一个祖先列表[1,2],7有一个祖先列表[1,3]

list1 = node1.getAncestorList()
list2 = node2.getAncestorList()

minlength = min(list1.size(), list2.size())
for (int i = 0; i < minlength; i++) {
    e1 = list1.getItemAt(i);
    e2 = list2.getItemAt(i);
    if (e1 == e2) ec = e1;
}
return ec;
list1=node1.getAncestorList()
list2=node2.getAncestorList()
minlength=min(list1.size(),list2.size())
对于(int i=0;i

因为它们都有相同的根祖先。所以你不需要关心不同的深度。您总是可以找到最上面的(n)个相同的祖先。祖先(n)是最新的共同祖先。

我通常会这样做:

首先计算
f[i][j]
,它表示节点
i
的第二个父节点
2^j
。我们有

f[i][j] = f[f[i][j - 1]][j - 1]
现在我们可以在
log(n)
time中获得节点i的
j-th
父节点

我们需要每个节点的深度,比如说
h[i]

上述操作可以在一个简单的
dfs()
中完成,复杂性为
O(N*Log(N))

然后,对于每个询问节点(i)和节点(j)LCA的查询(i,j),想象两个猴子站在树中,试图到达同一个节点

  • 首先让它们处于同一高度,然后我们知道它们需要站起来 相接的高度相同
  • 当它们不在同一节点时,尽可能多地攀爬
  • 他们当前所在节点的父节点是LCA
  • 您可以参考以下内容:

    int query(int u, int v){
        if(h[u]>h[v])swap(u,v);
        v = getUp(v,h[v]-h[u]);
        for(int i=log(n);i>=0;i--){
            if(f[u][i]!=f[v][i]){
                u=f[u][i];
                v=f[v][i];
            }
        }
        while(u!=v){
            u=f[u][0];
            v=f[v][0];
        }
        return u;
    }
    
    这里
    getUp(i,j)
    意味着找到节点i的
    j-th
    父节点,正如我们前面提到的,它可以

    int nt(int u,int x){
        for(int i=log(n);i>=0;i--){
            if((1<<i)<=x){
                u=f[u][i];
                x-=(1<<i);
            }
        }
        return u;
    }
    
    intnt(intu,intx){
    对于(int i=log(n);i>=0;i--){
    
    如果((1从普通深度优先搜索算法开始:

    public Node find(Node node, int target) {
        if(node == null || node.value == target) {
            return node;
        }
        if(node.value > target) {
            return find(node.left, target);
        } else {
            return find(node.right, target);
        }
    }
    
    现在,将其调整为两个“目标”参数,即target1和target2

    当搜索target1时向左,搜索target2时向右,你就找到了生命周期评价

    这假设两个目标都确实存在。如果需要断言它们确实存在,则需要在找到潜在LCA后继续搜索

    public Node findLca(Node node, int t1, int t2) {
        if(node == null) {
            return null;
        }
        if(node.value > t2 && node.value > t1) {
            // both targets are left
            return findLca(node.left, t1, t2);
        } else if (node.value < t2 && node.value < t1) {
            // both targets are right
            return findLca(node.right, t1, t2);
        } else {
            // either we are diverging or both targets are equal
            // in both cases so we've found the LCA
            // check for actual existence of targets here, if you like
            return node;
        }
    }
    
    公共节点findLca(节点节点,int t1,int t2){
    if(node==null){
    返回null;
    }
    if(node.value>t2&&node.value>t1){
    //两个目标都留下了
    返回findLca(node.left,t1,t2);
    }else if(node.value
    像这样的问题无非是一个有争议的问题。你愿意走多远?在该领域阅读几篇论文是否合适?添加库依赖项会产生太多开销?是吗?这会继续吗?你做得比(A)找到从根节点到每个节点的路径(b)更好识别两条路径中最长的公共前缀(前缀中的最后一个顶点是最近的公共祖先)。如果两个输入节点不在同一深度,该怎么办?您需要一种方法来确定两个祖先列表发散的位置。@chepner,简单地说,“比较每个元素”步骤需要处理不同长度的列表。这是“查找这两个列表中存在的最大数字”最小的公共元素。我们确定每个节点都有唯一的数字吗?如果没有,第一个公共祖先的每个子树中可能有相同的数字。是的,让我们小心我们所说的“数字”是什么意思“.OP图中的节点ID总是以1作为根,但你是对的,最小的公共值。我们可以确定节点对象是唯一的。我认为上面的“数字”只是不同节点的一个简短名称。我非常喜欢你的解释。但是在find方法中,你不应该让if(Node==null)返回null;?@Student我有
    if(Node==null)返回节点
    ,这是等效的。这不是假设树是BST吗?这没有回答问题。您正在执行深度优先搜索,这在尝试获取节点的祖先时没有意义,因为您需要遍历节点的父节点以获得LCA算法。DPS遍历节点的子节点。LCA问题是获取leas它不是共同的祖先,所以你必须穿越父母。