我在接受采访时被要求查找单个链表是否有循环。我搜索了这个SO并找到了几个答案采访问题:如何检测链表中的循环?我以前就知道这些答案但不知何故我回答的不同之处在于我的讨论朋友很久以前回来了,但我不确定答案是否正确。如果自己尝试,它按预期工作。不知何故,面试官并不开心。有人可以澄清这有什么问题吗?
struct node {
int flag;
struct node *next;
}
我的想法是不要使用两个指针并且可变地跳转,而是使用单个指针并遍历每个节点,例如:
node = node->next;
只有当我遍历节点并每次检查时,我才会将标志变量设置为1,例如
if (node->flag)
{
return TRUE; // implies list is a loop
}
else{
node->flag = 1;
}
除了效率之外,这种方法有什么问题?
答案 0 :(得分:3)
您需要为每个列表项存储其他数据(flag
)。因此,您的方法需要额外的O(N)内存,而使用两个指针的方法只需要O(1)内存。
所以你的方法不是内存效率。
答案 1 :(得分:2)
您的方法更有效,但依赖于您可以修改列表表示的事实。当被问到同样的问题时,我给出了相同的解决方案,但是面试官告诉我,我不允许以任何方式修改列表。
答案 2 :(得分:1)
您正在使用一个额外的整数变量flag
并说明您机器中的sizeof(int)
是否为4个字节,并且说您在链表中有100,000个节点,那么您将最终使用400,000个字节更多。那将是大约390M / .38G
要为链表中的所有节点重置flag
,即使它是O(n),您也必须遍历所有100,000个节点。这是一个开销。
现在,如果你将基于flag
的解决方案与2变量解决方案进行比较,那么它的计算时间几乎相同,但是2变量解决方案被认为是非常高效的内存,因为它不使用390M内存来实现识别循环!
答案 3 :(得分:1)
你的答案没有错,而是使用两个指针,它只使用一个指针。但是,对于面试来说,给出这个问题的答案就是一个基本的前提。
在绝对必要的情况下,通常不应该改变您所提供问题的数据结构。从这个角度考虑它。
如果它不是链接列表,而是该公司开发的应用程序,并且他们需要您找出某个特定的东西是否适用于该应用程序,该怎么办?在这种情况下,他们不希望您更改应用程序代码(因为除非不可避免,否则这是不切实际的)但是希望您能够解决您所拥有的问题。
因此,你的面试官对答案不满意。除了其他答案之外,您总是可以给出这个答案,但不能作为您选择的答案。
答案 4 :(得分:1)
也许Hare and Turtle
可行。 Turtle
通常在列表中进行交互,一次只进行一项,而Hare
进行速度提高两倍,一次进行两项。如果Hare
通过了Turtle
,则会有一个循环。
修改:我看到此建议已经here,并且OP在评论中已经被OP拒绝了。