检查2个树节点是否相关(即祖先 - 后代)
就是这样。我将在下面讨论我的解决方案(方法)。如果你想先考虑自己,请停止。
对于预处理,我决定进行预订(先递归遍历根,然后是子),并为每个节点提供标签。
让我详细解释标签。每个标签将由逗号分隔的自然数组成,如“1,2,1,4,5” - 此序列的长度等于(节点的深度+ 1)。例如。根的标签是“1”,root的子标签有“1,1”,“1,2”,“1,3”等。下一级节点将有“1,1,1”等标签,“1,1,2”,......,“1,2,1”,“1,2,2”,......
假设节点的“订单号”是其父节点的子列表中的“此节点的基于 1的索引”。
通用规则:节点的标签由其父标签后跟逗号和节点的“订单号”组成。
因此,为了回答O(1)中两个节点是否相关(即祖先 - 后代),我将检查其中一个节点的标签是否是“前缀”的其他的标签。虽然我不确定这些标签是否可以被认为占据O(N)空间。
任何有批评或替代方法的评论家都会受到期待。
答案 0 :(得分:17)
你可以在O(n)预处理时间和O(n)空间中使用O(1)查询时间,如果你存储每个顶点的预订编号和后序编号并使用这个事实:
对于树T的两个给定节点x和y,x是y的祖先,如果和 只有当x在t的前序遍历和y之后出现在y之前 在后序遍历中。
(来自此页:http://www.cs.arizona.edu/xiss/numbering.htm)
在最坏的情况下你做的是Theta(d),其中d是较高节点的深度,因此不是O(1)。空间也不是O(n)。
答案 1 :(得分:1)
如果考虑树中节点有n / 2个孩子的树(比方说),设置标签的运行时间将与O(n * n)一样高。所以这种标签方案不会起作用....
答案 2 :(得分:0)
线性时间最低的共同祖先算法(至少是离线)。比如看看here。您还可以查看tarjan's offline LCA algorithm。请注意,这些文章要求您事先了解将要执行LCA的对。我认为还有在线线性时间预计算时间算法,但它们非常复杂。例如,对于范围最小查询问题存在线性预计算时间算法。据我记得,这个解决方案两次通过LCA问题。该算法的问题在于它具有如此大的常数,它需要大量输入实际上比O(n * log(n))算法更快。
有一种更简单的方法需要O(n * log(n))额外的内存并再次以恒定时间回答。
希望这有帮助。