题目

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

思路分析

判断一个链表是否有环,有两种方法,一种借助哈希表,另一种则是使用快慢指针。

哈希表

我们定义一个哈希表,用来存储所有已经访问过的节点,每次遍历到一个节点时,判断该节点是否已经存在于哈希表中,如果已经存在,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到遍历完整个链表。

  1. const hasCycle = function(head) {
  2. // 使用 ES6 的 Map 数据结构定义一个哈希表
  3. const map = new Map();
  4. while(head) {
  5. // map 中是否已经存在当前节点
  6. if (map.has(head)) {
  7. return true;
  8. } else {
  9. // 当前节点在 map 中不存在,将当前节点添加到 map 中
  10. map.set(head, head);
  11. }
  12. // 通过链表的 next 指针获取下一个节点
  13. head = head.next;
  14. }
  15. return false
  16. };

快慢指针

我们定义两个指针,一个快指针,一个慢指针。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针和快指针同时指向 head 。

1、首先,快指针每次向前移动两步,慢指针每次向前移动一步,进行遍历整个链表;
2、在遍历的过程中,当快指针的 next 节点为 null ,或者快指针本身节点为 null 时,说明该链表没有环,遍历结束;
3、两个指针在移动的过程中,如果快慢指针相遇,也就是快指针反过来追上了慢指针,说明链表有环。当快慢指针相遇时,遍历结束。

  1. const hasCycle = function(head) {
  2. if (!head) return false;
  3. // 慢指针 初始时指向 head
  4. let slow = head;
  5. // 快指针 初始时指向 head
  6. let fast = head;
  7. // 快指针本身节点不为 null 并且 快指针的 next 节点也不为 null,继续遍历链表
  8. while(fast && fast.next) {
  9. // 慢指针向前移动一步
  10. slow = slow.next;
  11. // 快指针向前移动两步
  12. fast = fast.next && fast.next.next;
  13. // 当快慢指针相遇时,它们指向同一个节点,返回 true,说明链表有环
  14. if (slow && slow === fast) return true;
  15. }
  16. return false;
  17. }