142.环形链表II
代码随想录解析
题目:
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
解析:
一:通过两指针fast和slow,fast一次走两个单位,slow一次走一个单位看两者是否相遇,若相遇则有环,若不相遇则无环。
①:若无环返回 NULL。
②:若有环
二:若有环通过两指针index1,index2。index1指向head,index2指向fast,index1和index2同时以1的速度移动,相遇即为入环第一个节点处。不过我没有用index1,index2而是直接将slow指向head移动slow,fast直到相遇。
1: slow指针走过的节点数为: x + y, fast指针走过的节点数:x + y + n (y + z)
解释:
slow而言:相对fast而言静止,在没走完一圈时就会被赶上(fast走一圈slow才走半圈,在思考fast最后一下跳过slow时,若最后一下跳过,则前一个位置slow,fast重合,若最后一下没有跳过slow,你怎么自然就是重合(抽象理解:fast相对slow一次移动一个位置更不可能跳过))。只会走y距离不会走y加上n圈的距离。
fast而言:当两者都进入圈内,相对而言slow不动,fast以速度为1来追赶slow,所以必然相遇,同时只耗费一段距离或者刚好相遇。
如果x很长,y+z很短fast会先跑N圈,当slow进入圈内,再实现追赶,在圈内只耗费一段距离或者刚好相遇(通过将两者相对来思考)。
fast指针至少要多走一圈才能相遇slow指针。
2: 因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:公式:(x + y) * 2 = x + y + n (y + z)
整理公式之后为如下公式:x = (n - 1) (y + z) + z
n分为两种情况(n始终大于0):
①:当 n等于1,从相遇点设置一个指针,从head节点处设置一个指针,统一移动每次移动一个单位,当两者相遇即入环第一个节点(当起始点移动 x 的长度到达入环第一个节点处,相遇点指针移动了 z 的长度到达入环第一个节点处,此时两者相遇相遇)。
②:当 n 大于1,y+z为一圈的长度,同理:从相遇点设置一个指针,从head节点处设置一个指针,统一移动每次移动一个单位,当两者相遇即入环第一个节点(当起始点移动 x 的长度到达入环第一个节点处,相遇点指针移动了 z 的长度加上(n-1)圈的长度入环第一个节点处,此时两者相遇)。
总结就是:两个指针每次走一个单位,然后相遇,相遇点即入环第一个节点。
关键在于公式的分析:x = (n - 1) (y + z) + z
使用指针的移动模拟长度,重点在于移动后两者能刚好在入环第一个节点处相遇。
代码:
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head;
ListNode *slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
slow = slow->next;
if(fast == slow){
slow = head;
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return slow;
}
}
return NULL;
}
};