给定是二叉树和LCA,找到具有此LCA的节点对的数量?

时间:2014-03-03 14:52:37

标签: algorithm binary-search-tree

考虑如下定义的无限二叉树。

  

对于标记为v的节点,让其左子节点表示为2 * v,其右子节点表示为2 * v + 1。树的根标记为1。

     

对于给定的n个范围[a_1,b_1],[a_2,b_2],... [a_n,b_n],对于所有i,(a_i< = b_i),每个范围[a_i,b_i]表示a所有整数的集合不小于a_i且不大于b_i。例如,[5,9]代表集合{5,6,7,8,9}。

     

对于某个整数T,让S代表所有i到n的并集[a_i,b_i]。   我需要找到S中元素x,y的唯一对的数量(不论顺序),使得lca(x,y)= T

(维基百科对两个节点的LCA有很好的解释。)


例如,输入:

A = {2, 12, 11}
B = {3, 13, 12}
T = 1

输出应为6.(范围为[2,3],[12,13]和[11,12],它们的并集是{2,3,11,12,13}。在所有20对可能的对中,其中正好有6对((2,3),(2,13),(3,11),(3,12),(11,13)和(12,13)) LCA的1。)

输入:

A = {1,7}
B = {2,15}
T = 3

输出应为6.(给定范围为[1,2]和[7,15],它们的并集是{1,2,7,8,9,10,11,12,13}在110对可能的对中,正好有6对((7,12),(7,13),(12,14),(12,15),(13,14)和(13, 15))的LCA为3.)

1 个答案:

答案 0 :(得分:1)

嗯,使用这种递归方法计算符号中两个节点的LCA非常简单:

int lca(int a, int b) {
    if(a == b) return a;
    if(a < b) return lca(b, a);
    return lca(a/2, b);
}

现在要找到集合的联合,我们首先需要能够找到特定范围所代表的集合。让我们为此介绍一种工厂方法:

Set<Integer> rangeSet(int a, int b){
    Set<Integer> result = new HashSet<Integer>(b-a);
    for(int n = a; n <= b; n++) result.add(n);
    return result;
}

这将返回包含范围中包含的所有整数的Set<Integer>

要找到这些集合的并集,只需将addAll个元素集合到一个集合中:

Set<Integer> unionSet(Set<Integer> ... sets){
    Set<Integer> result = new HashSet<Integer>();
    for(Set<Integer> s: sets)
        result.addAll(s);
    return result;
}

现在,我们需要遍历集合中所有可能的对:

pairLcaCount(int t, Set<Integer> nodes){
    int result = 0;
    for(int x: nodes)
        for(int y: nodes)
            if(x > y && lca(x,y) == t) result++;
    return result;
}

其他一切只是胶合逻辑,从输入要求转换为此处所需的方法。例如,像:

Set<Integer> unionSetFromBoundsLists(int[] a, int[] b){
    Set<Integer> [] ranges = new Set<Integer>[a.length];
    for(int idx = 0; idx < ranges.length; idx++)
        ranges[idx] = rangeSet(a[idx], b[idx]);
    return unionSet(ranges);
}