26. 环形链表 II(学习)
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
提示:
链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引
解析:
一、初始化:
1.slow指针:指向链表的头节点head。
2.fast指针:也指向链表的头节点head。
二、移动指针:
1.在每一步中,slow指针向前移动一步(slow = slow.next)。
2.同时,fast指针向前移动两步(fast = fast.next.next)。
三、检测环:
1.如果链表中没有环,fast指针最终会到达链表的末尾(fast或fast.next为null),此时返回null。
2.如果链表中存在环,slow和fast指针最终会在环内的某个位置相遇。
四、找到环的起始节点:
1.一旦slow和fast相遇,我们知道链表中存在环。
2.此时,将slow(或fast,但为了避免混淆,我们一般使用新的指针)重新指向链表的头节点head。
3.然后,同时以一步为单位移动slow(或新指针)和重新定位的指针,直到它们再次相遇。
4.相遇点即为环的起始节点。
var detectCycle = function(head) {
if (!head || !head.next) {
return null; // 空链表或只有一个节点的链表肯定没有环
}
let slow = head;
let fast = head;
// 判断链表是否有环
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) {
// 找到环的起始节点
let ptr1 = head;
let ptr2 = slow;
while (ptr1 !== ptr2) {
ptr1 = ptr1.next;
ptr2 = ptr2.next;
}
return ptr1; // 或 ptr2,此时它们相等
}
}
return null; // 没有环
};