这是一道非常常见的面试题,嗯,经典的链表问题。

最简单直观的办法需要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)的空间,但是需要对原链表做些修改,嗯,实际上破坏了原链表的结构。那就是,反转原链表,如果原链表有环,那么在反转过程中,最终你会到达原链表的第一个结点,即头结点。---接下来会有文章讨论如何反转一个单链表,递归和非递归两种形式。

插句话:这种方法真心蛋疼!

 

posted on 2013-06-25 16:53  老刘++  阅读(236)  评论(0编辑  收藏  举报