查找树中所有最长的唯一路径

时间:2015-08-19 08:49:42

标签: algorithm data-structures tree

让我们假设我们有一个由N个节点组成的树。任务是找到树中所有最长的唯一路径。例如,如果树如下所示:

Sample Tree

然后树中有三条最长的独特路径:1 - 2 - 3 - 4 - 5,6 - 2 - 3 - 4 - 5和1 - 2 - 6.

我想以编程方式查找并存储给定树的所有此类路径。 一种方法是计算树中每对节点之间的路径,然后拒绝任何其他路径中包含的路径。但是,我正在寻找一种有效的方法。我的问题如下:

  • 是否可以在小于O(N ^ 2)的范围内计算此信息?我还没有想到一个比O(N ^ 2)更快的解决方案。
  • 如果是的话,你能否引导我找到解决方案。

我想试试的原因是因为我试图解决这个问题:KNODES

6 个答案:

答案 0 :(得分:2)

时间复杂度低于O(N^2) 的算法只有才存在,如果具有N个节点的树的每个解决方案都可以编码为小于O(N^2)空间。

假设有n的完整二叉树离开(N=n log n)。该问题的解决方案将包含每组2个叶子的路径。这意味着,该解决方案将具有O(n^2)个元素。因此,对于这种情况,我们可以将解决方案编码为2元素的叶子集。

现在考虑一个带有m叶子的几乎完整的二叉树,它是通过仅用n叶子从完整二叉树中删除任意叶子而创建的。将此树的解与完整二叉树的解比较时,两者将共享一组可能为空的路径。事实上,对于完整二叉树的解的每个路径子集,将存在至少一个具有如上所述的m叶的二叉树,其包含这种子集的每个解。 (我们故意忽略这样一个事实,即m个叶子的树在解决方案中可能有更多的路径,其中至少有一些路径末端不是完整二叉树的叶子。)

只有具有m的二叉树的解的那部分将由具有(n^2)/2位的数字编码。此数字中的位索引表示矩阵的右上半部分中具有n列和行的元素。

对于n=4,这将是:

x012
xx34
xxx5

如果解决方案中包含无向路径i,则将设置索引row(i),column(i)处的位。

正如我们已经声明,具有m叶子的树的解决方案可能包含具有n>=m叶子的完整二​​叉树的解决方案的任何子集,每个二进制数都带有(n^2)/2位将代表具有m叶子的树的解决方案。

现在使用小于(n^2)/2的{​​{1}}位编码每个可能的数字是不可能的。所以我们已经证明解决方案至少需要(n^2)/2空间来表示。使用上面的O(n^2),我们产生的空间要求至少为N=n log n

因此 doens't 存在时间复杂度小于O(N^2)的算法

答案 1 :(得分:1)

据我所知,你有一棵没有选定根的树。您的可允许路径是不允许两次访问树节点的路径(不允许返回)。并且您需要找到所有这些不允许路径的子路径的可允许路径。

因此,如果我理解正确,那么如果一个节点只有一条边,那么该可允许的路径在该节点处开始或停止。如果连接了树,则可以通过一个允许的路径从任何节点到达任何节点。

因此,您选择具有一条边的所有节点,将其称为S.然后选择S中的一个并遍历整个树,保存到两端的路径(路径,而不是步行顺序)。然后对S中的每个其他项执行此操作并删除重复的路径(它们可以按相反的顺序排列:例如从1:1 - 2 - 6开始,从6:6 - 2 - 1开始)。

所以在这里你必须访问树中的所有节点,就像在树中有叶子一样。因此复杂性取决于分支因子(在最坏的情况下它是O(n ^ 2)。有一些优化可以减少操作量,就像你不必从最后一个S走树一样。

答案 2 :(得分:0)

enter image description here

在此图片中,最长路径为{1,2,3,4},{1,2,3,5},{1,2,3,6},{1,2,3,7}, {1,2,3,8},{1,2,3,9},{1,2,3,10}

对于像这样存储所有最长路径的树将花费你O(N 2

答案 3 :(得分:0)

假设您的图片上有二叉树。

class Node(object):
  def __init__(self, key):
    self.key = key
    self.right = None
    self.left = None
    self.parent = None

  def append_left(self, node):
    self.left = node
    node.parent = self

  def append_right(self, node):
    self.right = node
    node.parent = self

root = Node(3)
root.append_left(Node(2))
root.append_right(Node(4))
root.left.append_left(Node(1))
root.left.append_right(Node(6))
root.right.append_right(Node(5))

我们需要获得所有叶子之间的所有路径。所以在你的树上它们是:

  • 1,2,6
  • 6,2,3,4,5
  • 1,2,3,4,5

您可以在(编辑:非线性,二次)时间内执行此操作。

def leaf_paths(node, paths = [], stacks = {}, visited = set()):
  visited.add(node)

  if node.left is None and node.right is None:
    for leaf, path in stacks.iteritems():
      path.append(node)
      paths.append(path[:])
    stacks[node] = [node]
  else:
    for leaf, path in stacks.iteritems():
      if len(path) > 1 and path[-2] == node:
        path.pop()
      else:
        path.append(node)

  if node.left and node.left not in visited:
    leaf_paths(node.left, paths, stacks, visited)
  elif node.right and node.right not in visited:
    leaf_paths(node.right, paths, stacks, visited)
  elif node.parent:
    leaf_paths(node.parent, paths, stacks, visited)

  return paths

for path in leaf_paths(root):
  print [n.key for n in path]

树的输出将是:

  

[1,2,6]

     

[6,2,3,4,5]

     

[1,2,3,4,5]

这个想法是在遍历树时跟踪所有访问过的叶子。并保持每个叶子的堆栈路径。所以这是内存/性能权衡。

答案 4 :(得分:0)

让我们看看具有n个节点和n-1边缘的星形树。

然后你有C(n-1, 2)个独特的最长路径。

因此复杂性的下限不能小于O(n ^ 2)。

答案 5 :(得分:0)

画树。设v是顶点,p是其父节点。最长路径的长度包括v但不是p =(v的左子树的高度)+(右子树的高度为v)。

所有v的最大值是图中最长的路径。您可以在O(n)中计算:

首先计算所有中间高度。从树叶开始处理:(高度低于v)= 1 + max(高于左子,高度低于右子)

然后计算每个顶点v的和(v的左子树的高度)+(右子树的高度v),并取最大值。这是图中最长路径的长度。