「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
题目_142. 环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
思路:
申明一个存储空间,访问每一个节点,如果数组中没有这个节点,那么就将他放进这个数组,如果遇到存储空间中有这个节点,那么则判断该链表有环,并返回这个重复节点即可。
这里存储空间可以用数组,也可以用Set和Map。
暴力解法代码
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
let temp = new Set();
let cur = head;
while(cur){
if(temp.has(cur)){
return cur;
}
temp.add(cur);
cur = cur.next;
}
return null;
};
双指针解法
思路:
首先看下图
建立两个指针fast和slow,fast每次走两步,slow每次走一步,假设两者在fast入环n圈之后相遇在如图bc中间紫色的点,那么可以得出
slow走过距离为a+b
fast走过距离为a+n(b+c)+b
又因为fast的速度为slow的两倍,则有如下等式
2(a+b) = a+n(b+c)+b => a = c + (n-1)(b+c)
那么我们发现当两个指针相遇的时候,再创建一个指针test,他每次走一步,当test和slow相遇的时候,那个位置就刚好是入环点
这里解法理解起来,主要就是要先找到上面这个等量公式,然后想明白即可。
题解代码
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function(head) {
if (head === null) {
return null;
}
let slow = head, fast = head;
while (fast !== null) {
slow = slow.next;
if (fast.next !== null) {
fast = fast.next.next;
} else {
return null;
}
if (fast === slow) {
let test = head;
while (test !== slow) {
test = test.next;
slow = slow.next;
}
return test;
}
}
return null;
};