这是一道非常常见的面试题,嗯,经典的链表问题。
最简单直观的办法需要O(N^2)的时间和O(N)的空间,即储存所有访问过的结点,每当访问到一个新的结点时,与所有储存的结点依次比较即可。
这个方法看上去不那么高明,提示一下,最优解法只需要O(N)的时间和O(1)的空间。再提示一下,对于链表问题,很有用的一种方法就是用两个指针(快慢指针)来遍历链表!
现在让我们来看看这个最优解法吧!
之前已经提到了,最优解法只需要O(N)的时间和O(1)的空间。它使用两个指针,快慢指针。慢指针每次向前走一步,而快指针走两步。如果单链表存在环,那么最终,快结点和慢结点会相遇。换句话说,如果单链表没环,那么快结点会在慢结点之前,到达单链表的最后一个结点( ->next为NULL)。
代码如下:
bool
hasLoop(Node *head) {
Node *slow = head, *fast = head;
while
(slow && fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if
(slow == fast)
return
true
;
}
return
false
;
}
这个优美的算法被称为Floyd’s cycle finding algorithm, 也可以叫做 the Tortoise and hare algorithm.
其它的解法:
另外一种算法也可以达到O(N)的时间和O(1)的空间,但是需要对原链表做些修改,嗯,实际上破坏了原链表的结构。那就是,反转原链表,如果原链表有环,那么在反转过程中,最终你会到达原链表的第一个结点,即头结点。---接下来会有文章讨论如何反转一个单链表,递归和非递归两种形式。
插句话:这种方法真心蛋疼!