题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
问题1:如何判断链表是否有环
可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 这个链表有环,由于fast 和 slow的速度差,指针会在环中相遇。
问题2:如何确定环的入口
slow走过的路程为 :x+y
fast走过的路程:x+y+n(z+y);n为快指针比慢指针多走的圈数
快指针的速度是慢指针的两倍(慢指针走两圈,快指针走一圈);因此:
fast指针走过的节点数 = slow指针走过的节点数 * 2;
慢指针进入环后,在一圈之内会与快指针相遇;
2*(x+y)=x+y+n(z+y);
x+y=n(z+y);
x=(n-1)(z+y)+z;
设n为1即可得x=z;(这一步是为了找到快慢相遇点,n的数量不影响下列结论,n的数量只影响index1在环内的圈数)
定义一个指针index1,在头结点处定一个指针index2。让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};