我们给出了多图的邻接列表,G =(V,E),需要找到一个O(V + E)算法来计算等效无向图的邻接列表。
到目前为止,我已经想到了一个大小为| V |的数组以便在adj [u]中标记至少遇到过一次的顶点,从而防止重复。在遍历每个adj [u]之前重置该数组。但是,我想知道是否存在更好的算法,不使用额外的空间。请建议。
答案 0 :(得分:1)
如果您希望实现O(V+E)
时间复杂度,则没有更好的算法,因为这基本上是element distinctness problem的变体,可以通过在O(nlogn)
中排序来解决,或者在O(n)
中使用O(n)
个额外空格。
因此,要实现O(V + E)时间,您的算法是最优的(就大O符号而言)
答案 1 :(得分:1)
作为参考,应该注意从技术上讲,每次重置阵列时都会使用O(V)时间。数组创建在技术上是免费的,因为它是使用随机指针创建的,不能保证这些值是什么。因此它需要一次传递来实际初始化它们0或null。因此,对于您提出的算法,运行时间变为O(V ^ 2)。
我知道这个问题现在已经解决了,但是应该注意这个事实。
答案 2 :(得分:0)
您可以使用无序设置数据结构,通过仅检查邻居列表中没有添加两次邻居来将O(n)额外空间改进为O(最大邻居数)。
答案 3 :(得分:0)
遇到同样的问题。
在思考之后,我想建议你的解决方案快速修复一下。正如@sunnytheit所提到的 - 在两个不同邻接列表之间的每两次迭代之间,你必须重置指示数组。这个动作确实需要$ \ Theta(| V |)$(总计为多项式运行时复杂度)。要修复它,您可以使用与数组并行的堆栈。
一旦到达当前adj-list中的顶点,首先要检查它是否位于数组中,如果是,则继续下一个邻居。如果没有,则将其推入堆栈并更新阵列中的指示值。
当您在当前的调整列表上运行完毕后,您希望在该调整列表中弹出您遇到的元素,并为每个值重置数组中的相应值。
总计,它总计两次超过图的边缘。所以,最后运行时的复杂性将是$ \ Theta(| V | + | E |)$。
备注:您可以使用某种BST而不是数组来节省额外空间 - 但您必须分析其对运行时复杂性的影响。