【问题标题】:Identify node lies between two other node识别节点位于另外两个节点之间
【发布时间】:2014-08-12 00:19:13
【问题描述】:

给出了树。边信息以邻接表格式给出。

节点编号在 1, 2, 3, ....N.

树的根总是 1。

现在,给出了两个索引。问题是上述两个中的任何一个索引是否位于从根(1)到其他索引的路径上。

约束

  1. 节点数为 10^5。
  2. 可以触发的最大查询数,10^5。
  3. 父 ID 始终小于子 ID。

示例:-

给定的边缘:-

1 2
2 5
1 3
3 7
1 4
4 8
8 9

问题 -

2 3  ( Answer - Not possible, from 1 to 2, 3 never comes in between and from 1 to 3, 2 never comes in between.)
8 9  ( Answer - Possible, 8 lies in between 1 and 9)

下一个例子:-

1 2
2 4
2 5
1 3
3 6
3 7
3 8

【问题讨论】:

  • 你是否有一个特殊的边到父节点的关系,比如node.parent,或者是父节点的ID总是小于子节点的ID,还是边总是在形成(parent, child)?在这些情况下,您可以直接“向上”,直到找到根节点或其他节点。
  • 没有提到这种关系。但是,如果我按照您所说的那样进行迭代,那么在最坏的情况下,每个查询都需要 O(节点总数)。
  • 在最坏的情况下,树是一个链。在一般情况下,它应该是 O(logn)。
  • 你有没有其他方法,通过存储一些东西来减少查询响应时间?
  • 好吧,你当然可以总是缓存一些东西,比如创建一个 hashmap(nodeid -> 父节点集),然后查找是 O(1),但这需要大约 O(nlogn) 空间,除非我弄错了。

标签: algorithm


【解决方案1】:

算法如下:-

  1. 从根目录开始,记下每个节点的IN TIMEOUT TIME。正如你所说,给出了邻接列表。您可以通过在时间复杂度 O(Total number of nodes ) 中使用 DFS 轻松完成。
  2. 一个节点“B”是另一个节点“A”的后代,仅在一种情况下。

    IN_TIME(A)

这样,Query 将在 O(1) 时间内处理。

【讨论】:

  • 感谢您的高效解决方案。
  • 好主意,实际上似乎有道理。但是,恕我直言,您的回答有点难以理解。 +1 如果您添加更多解释(例如,进出时间的确切含义)或一些伪代码,那么它对未来的访问者更有帮助
【解决方案2】:

假设父节点的ID(更靠近根的那个)总是大于子节点的ID,就像你的例子中的情况一样,你可以很容易地从任何边缘看到它是否引向根部或远离根部。因此,基本算法将是:

given nodes n and m
find edge (x, n) or (n, x) such that x < n
repeat with node x until x is m or x is root

我认为没有更快的方法来确定一个节点是否位于根节点和另一个节点之间。当然,您可以通过使用适当的数据结构来提高性能,例如,首先将每个节点映射到哈希集中的父节点。下面是一个 Python 示例:

ROOT = 1
edges = ((1, 2), (2, 4), (2, 5), (1, 3), (3, 6), (3, 7), (3, 8))

parents = {}
for edge in edges:
    parent, child = min(edge), max(edge)
    parents[child] = parent

def is_anchestor_of(p, c):
    while c > p:
        if parents[c] == p:
            return True
        c = parents[c]
    return False

创建哈希映射的时间和空间复杂度在节点或边的数量上为 O(n)(在树中几乎相同),is_anchestor_of 的平均案例复杂度为 O (logn),但在最坏的情况下(极度不平衡的树或链)会恶化到 O(n)。

您可以通过将每个节点映射到它的所有锚点来提高查找复杂性。创建这个哈希映射的复杂性是 O(n log n),除非我在时间和空间上都弄错了,但在最坏的情况下可能会上升到 O(n^2)。无论如何,使用这种结构,is_anchestor_of 的复杂度是 O(1),因为它只是在哈希映射中查找,然后在哈希集中查找。

anchestors = {}
for node in parents:
    anchestors[node] = set([ ROOT ])
    p = parents[node]
    while p != ROOT:
        anchestors[node].add(p)
        p = parents[p]

def is_anchestor_of(p, c):
    return p in anchestors[c]

在这两种情况下,只需检查一个是否是另一个的锚。

def on_one_path(x, y):
    return is_anchestor_of(x, y) if x < y else is_anchestor_of(y, x)
print on_one_path(3, 8)

更新:似乎有更有效的方法;请参阅@Loha 的 答案。

【讨论】:

  • 但在最坏的情况下,它需要多项式复杂度。在我的情况下它会失败。
  • @devnull 我要问这个:你有理由相信有更快的算法吗?如果是这样,它会是什么样子?最坏的情况真的与您相关吗?您是否尝试实现该算法并查看您的树需要多长时间?
  • @devnull 想解释为什么投反对票?收到另一个(在您看来)比其他答案更好的答案并不意味着您需要对这些答案投反对票,除非它们包含错误的信息,而这两个答案都不是这种情况。如果必须,请删除赞成票,我什至认为这很粗鲁,但反对票是完全错误的。
  • 您给出的答案是一种幼稚的方法。我可以说你的答案是正确的,但对我没有用。我试图删除我的赞成票,但错误地它被否决了。你可以编辑一些东西,这样我就可以删除我的反对票。真的很抱歉。
  • @devnull 完成编辑。另外,如果答案如此“幼稚”,您为什么不写类似“我已经尝试过这个和这种幼稚的方法,但它们还不够”之类的东西?会为我节省很多的工作。
【解决方案3】:

对于每个节点,在树中构造它上面的节点的排序列表:

1 {}
2 {1}
3 {1}
4 {1}
5 {1, 2}
7 {1, 3}
8 {1, 4}
9 {1, 4, 8}

然后,当给出查询时,搜索列表中属于另一个的每个节点(O(logN)):

2 3: 2 is not in {1}, and 3 is not in {1}, so the answer is no.
8 9: 9 is not in {1, 4}, but 8 is in {1, 4, 8}, so the answer is yes.

编辑:

正如 tobias_k 所指出的,还有其他结构,例如哈希表,可以使搜索O(1)。构建表格是 O(n),很简单 - 只需遍历边列表并将它们放入。

【讨论】:

  • 或者一个哈希集,那么查找是O(1)。
  • @Beta 但是如何为每个节点索引列出所有父索引?
  • @Beta 你如何构造For each node, construct a sorted list of the nodes above it in the tree:
  • @Beta 很抱歉投了反对票。我试图删除我的赞成票,但错误地它变成了反对票。您能否进行一些编辑,以便我可以删除我的反对票。再次抱歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多