【问题标题】:Given is a binary tree and a LCA , find the number of pair of nodes which have this LCA?给定一棵二叉树和一个 LCA,找出具有该 LCA 的节点对的数量?
【发布时间】:2014-03-03 14:52:37
【问题描述】:

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

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

对于给定的 n 个范围 [a_1, b_1], [a_2, b_2], ... [a_n, b_n] 其中 (a_i

对于某个整数 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 ,14,15}. 在 110 个可能的对中,正好有 6 个 ((7,12), (7,13), (12,14), (12, 15), (13,14) 和 (13, 15)) 的 LCA 为 3。)

【问题讨论】:

  • 二叉树是它的根节点class Node { Node parent, first, second; }。您正在使用一些奇怪的符号,似乎是指您存储节点元素的数组索引,但树通常不会以这种方式存储在数组中。
  • 您能否提供一个链接来准确描述“LCA”的含义,或者描述您对“树”的表示法?
  • 数字不是树节点。
  • 我会尽力而为,在解决这个有趣的问题时请耐心等待。
  • 看到这里被问到这个问题真的很难过。这是我为在线测试设置的问题。测试刚刚结束,所以在测试期间就问了这个问题。我想将此添加为评论,但没有足够的声誉来做到这一点,因此将其作为答案。

标签: algorithm binary-search-tree


【解决方案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&lt;Integer&gt;,其中包含范围内的所有整数。

要找到这些集合的并集,只需将它们的元素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);
}

【讨论】:

  • 谢谢!它帮助了我。抱歉,我无法投票,因为我没有 15 名声望。
  • @MariaJones 尽管请注意此代码与最佳代码相差。我以最简单、快速和肮脏的方式做到了。对于大多数实际使用而言,此代码可能会慢得令人无法接受。如果需要更好的性能,请修改 lca 以缓存它已经计算的值(或使其计算更直接),并使用更薄(稀疏)的数据结构而不是集合。
  • 你帮助了我,这很重要! :D
  • @MariaJones 我还猜想你的教授可能期望的解决方案比这里找到的 O(n^2) 快得多。
猜你喜欢
  • 1970-01-01
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 2021-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-25
相关资源
最近更新 更多