题目
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
思路分析
判断一个链表是否有环,有两种方法,一种借助哈希表,另一种则是使用快慢指针。
哈希表
我们定义一个哈希表,用来存储所有已经访问过的节点,每次遍历到一个节点时,判断该节点是否已经存在于哈希表中,如果已经存在,则说明该链表是环形链表,否则就将该节点加入哈希表中。重复这一过程,直到遍历完整个链表。
const hasCycle = function(head) {
// 使用 ES6 的 Map 数据结构定义一个哈希表
const map = new Map();
while(head) {
// map 中是否已经存在当前节点
if (map.has(head)) {
return true;
} else {
// 当前节点在 map 中不存在,将当前节点添加到 map 中
map.set(head, head);
}
// 通过链表的 next 指针获取下一个节点
head = head.next;
}
return false
};
快慢指针
我们定义两个指针,一个快指针,一个慢指针。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针和快指针同时指向 head 。
1、首先,快指针每次向前移动两步,慢指针每次向前移动一步,进行遍历整个链表;
2、在遍历的过程中,当快指针的 next 节点为 null ,或者快指针本身节点为 null 时,说明该链表没有环,遍历结束;
3、两个指针在移动的过程中,如果快慢指针相遇,也就是快指针反过来追上了慢指针,说明链表有环。当快慢指针相遇时,遍历结束。
const hasCycle = function(head) {
if (!head) return false;
// 慢指针 初始时指向 head
let slow = head;
// 快指针 初始时指向 head
let fast = head;
// 快指针本身节点不为 null 并且 快指针的 next 节点也不为 null,继续遍历链表
while(fast && fast.next) {
// 慢指针向前移动一步
slow = slow.next;
// 快指针向前移动两步
fast = fast.next && fast.next.next;
// 当快慢指针相遇时,它们指向同一个节点,返回 true,说明链表有环
if (slow && slow === fast) return true;
}
return false;
}