让我们假设我们有一个由N个节点组成的树。任务是找到树中所有最长的唯一路径。例如,如果树如下所示:
然后树中有三条最长的独特路径:1 - 2 - 3 - 4 - 5,6 - 2 - 3 - 4 - 5和1 - 2 - 6.
我想以编程方式查找并存储给定树的所有此类路径。 一种方法是计算树中每对节点之间的路径,然后拒绝任何其他路径中包含的路径。但是,我正在寻找一种有效的方法。我的问题如下:
我想试试的原因是因为我试图解决这个问题:KNODES
答案 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)
在此图片中,最长路径为{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))
我们需要获得所有叶子之间的所有路径。所以在你的树上它们是:
您可以在(编辑:非线性,二次)时间内执行此操作。
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),并取最大值。这是图中最长路径的长度。