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

时间:2012-08-21 13:34:57

标签: java algorithm tree binary-tree

  

可能重复:
  How can I find the common ancestor of two nodes in a binary tree?
  first common ancestor of a binary tree

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

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

任何人都可以建议我应该如何处理并解决这个问题?

3 个答案:

答案 0 :(得分:15)

从普通的深度优先搜索算法开始:

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。

这假设两个目标确实存在。如果你需要声明他们这样做,你需要在找到潜在的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;
    }
}

答案 1 :(得分:1)

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

你应该制作一个getAncestorList()。它返回其祖先的列表顺序,例如。 4具有祖先List [1,2],并且7具有ancestorList [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;

因为他们都有相同的根祖先。所以你不需要关心不同的深度。你总能找到顶级(同一位)的祖先。和祖先(n)是最新的共同祖先。

答案 2 :(得分:0)

这是我通常做的事情:

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

f[i][j] = f[f[i][j - 1]][j - 1]

现在我们可以在j-th时间内获得节点i的log(n)父亲。

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

以上可以使用复杂度为dfs()的简单O(N*Log(N))完成。

然后对于询问节点(i)和节点(j)的LCA的每个查询(i,j),想象两只猴子在树中起床,尝试获取到同一节点。

  1. 首先让它们处于同一高度,然后我们知道它们需要起床 高度相同。
  2. 虽然他们不在同一个节点,但要尽可能多地攀爬。
  3. 他们目前所在节点的父亲是LCA。
  4. 您可以参考:

    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;
    }
    

    因此,对于非常查询,复杂性也是O(N*Log(N))