最快的非递归实施LCA?

时间:2017-01-01 20:23:49

标签: algorithm dictionary tree lowest-common-ancestor

这是我提出的用于非递归地找到二叉树中两个节点的最低共同祖先的算法。这是基本策略:

  1. 使用字典/哈希表来存储树。每个键值对代表一个节点及其父节点。
  2. 从两个节点中的每个节点开始,通过将表示每个节点的值的变量设置为其父节点的值来向上走树,将遍历值存储在散列集中(两个节点中的每一个都存在一个)。 / LI>
  3. 当达到以下任何条件时,搜索完成:(a)两个节点的值相等;或者(b)当两条路径相互交叉时(即,节点1的遍历值的散列集包含节点2的当前值,反之亦然);或者(c)传入的节点不存在于树中(在这种情况下,算法终止并返回-1)。
  4. 我的理解是我的算法的最坏情况时间和空间复杂度是O(log(n)),因为我们从来不需要在我们的hashsets中进行超过2 *个高度遍历或存储超过2 *个高度值(并且由于哈希集和树词典的查找时间是O(1))。

    以下是我的代码(C#)。请告知我的分析是否正确,或者是否有更有效(非递归)的方法:

    int LowestCommonAncestor(int value1, int value2, Dictionary<int, int> tree)
    {
        var value1Visited = new HashSet<int>();
        var value2Visited = new HashSet<int>();
        while (true)
        {
            if (value1 == value2) return value1;
            if (value1Visited.Contains(value2)) return value2;
            if (value2Visited.Contains(value1)) return value1;
    
            int nextValue1;
            int nextValue2;
    
            if (tree.TryGetValue(value1, out nextValue1))
            {
                //Walk node 1 up the tree:
                value1 = nextValue1;
                value1Visited.Add(value1);
            }
            else
            {
                //Node doesn't exist in tree:
                return -1;
            }
    
            if (tree.TryGetValue(value2, out nextValue2))
            {
                //Walk node 2 up the tree:
                value2 = nextValue2;
                value2Visited.Add(value2);
            }
            else
            {
                //Node doesn't exist in tree:
                return -1;
            }
        }
    }
    

3 个答案:

答案 0 :(得分:0)

  1. 从每个节点向上移动到根以测量其深度

  2. 从较深的节点向上移动路径,直到达到与较浅节点相同的深度。

  3. 从两个节点向上移动路径(即在两条路径上保持相同的深度),直到它们相遇为止。

答案 1 :(得分:0)

您不需要两个哈希集。

  1. 上去并在一个哈希集中收集一个节点的祖先
  2. 从第二个节点及其每个祖先上升,检查在步骤1中收集的路径是否包含第二个节点的当前祖先。停在第一个常见的那个。
  3. 当D是树的最大深度时,复杂性是O(D)最坏情况的复杂性。

    N个节点中最坏情况的复杂性 - 当树在列表中退化时,其中一个节点是该列表的头部,另一个节点是尾部。

    如果树是平衡的,则D = log(N) - log的基数是节点的后代数(binary-log2,ternary-log3等)。

答案 2 :(得分:0)

然后,这是我修改过的算法:

int LCA(int value1, int value2, Dictionary<int, int> tree)
{
    if (!tree.ContainsKey(value1) || !(tree.ContainsKey(value2))) return -1;

    int depth1 = 0;
    int depth2 = 0;
    int tmpVal1 = value1;
    int tmpVal2 = value2;

    while (tmpVal1 != -1)
    {
        tmpVal1 = tree[tmpVal1];
        depth1++;
    }

    while (tmpVal2 != -1)
    {
        tmpVal2 = tree[tmpVal2];
        depth2++;
    }

    if (depth1 > depth2)
    {
        while (depth1 > depth2)
        {
            value1 = tree[value1];
            depth1--;
        }
    }

    else if (depth2 > depth1)
    {
        while (depth2 > depth1)
        {
            value2 = tree[value2];
            depth2--;
        }
    }
    while (value1 != value2)
    {
        value1 = tree[value1];
        value2 = tree[value2];
    }

    return value1;
}