通过仅遍历一次,测试单个链表是否为圆形

时间:2013-06-30 10:15:59

标签: algorithm linked-list circular-list

我是一个更新鲜的人,我在最近的一次采访中被问到了这个问题。

问题是--- 通过遍历链表的每个元素,只需查看单个链表是否在任何时候都是循环的。

对此我回答说,我们将在遍历另一个链表中的列表时存储每个节点的引用,并且对于正在测试的列表中的每个节点,我们将查找列表中是否存在引用我存储引用。

采访者说他需要一种更优化的方法来解决这个问题。

有谁能告诉我什么是解决这个问题的更优化的方法。

PS:在任何时候通过循环我的意思是这个。 http://s22.postimg.org/g0iwevfnl/2013_06_30_15_56_34_362.jpg

4 个答案:

答案 0 :(得分:9)

面试官正在寻找你是否知道正式称为Floyd's cycle-finding algorithmTortoise and hare非正式的技巧。

这个想法是在一个循环中推进两个指针,一个每次迭代移动两次,另一个只移动一次。如果快速移动的指针从后面赶上缓慢移动的指针,则列表有一个循环。

此算法检测O(n)时间和O(1)存储中的周期。 “慢”指针通过列表不超过一次,所以可以说算法在单次遍历中找到答案。

在我看来,这个算法提出了一个糟糕的面试问题,因为除非你提前知道,否则在现场有点难以提出。与此同时,这不是一个广泛使用的算法,每个人都必须知道它,让我想知道为什么有人会在面试中询问它。

答案 1 :(得分:3)

我怀疑采访者的目标是看你是否知道 Floyd的循环发现算法。这样一个问题的目标是看你是否理解数据结构概念,如列表,二叉树和哈希。

你的答案的主要问题是你给出的算法的复杂度为O(n ^ 2),即遍历原始列表的O(n)* O(n)用于检查第二个节点是否存在列表,在每次迭代中。

当面试官要求您优化答案时,您可能建议用另一个提供比O(n)更快查找的数据结构替换第二个链表。例如,二叉树具有O(logn)查找复杂度并且散列具有O(1)查找复杂度(并非总是但这是常见假设),这明显快于使用具有查找复杂性的第二链接列表O(n)。

所以O(n)解决方案是用哈希(即HashMap,HashSet等)替换你的第二个链表。

当然 Floyd的循环查找算法是一个更优雅的解决方案,因为它具有更好的内存复杂性(即不需要将访问过的节点存储在内存中)。

答案 2 :(得分:1)

更有效的方法是使用单个迭代器和放大器。检查是否存在指向null的节点......这种方法应该比上述方法高出两倍。

答案 3 :(得分:0)

tempNode = list;

while((tempNode->next != list) && (tempNode->next != NULL))
     tempNode = tempNode->next;

if(tempNode->next == list)
   //list is circular
if(tempNode->next == NULL)
  //list is not circular

Above two conditions can be addressed in while loop also