原题
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
解题思路
两个关键点:该链路是否为环路,如果是的话,环路起始点在哪里?
1.判断是否有环路。用一个指针遍历结点,如果能走到头即没有回路(注意链路可能为空,所以不光要看fast->next,还要看fast是否为NULL),如果一直往下走即为有回路。
这里就会出现一个问题,有回路就会陷入死循环,解决方法就是使用快慢双指针。fast每次前进两步,
slow每次前进一步,如果能相遇即为有回路,不然慢指针永远追不上快指针(起始点都一样,所以不要用while循环)。快慢指针为何一定相遇,知乎上有用户进行了解答,一下是知乎上的解释:
1:快指针与慢指针之间差一步。此时继续往后走,慢指针前进一步,快指针前进两步,两者相遇。
2:快指针与慢指针之间差两步。此时继续往后走,慢指针前进一步,快指针前进两步,两者之间相差一步,转化为第一种情况。
3:快指针与慢指针之间差N步。此时继续往后走,慢指针前进一步,快指针前进两步,两者之间相差(N+1-2)-> N-1步。因此,此题得证。所以快指针必然与慢指针相遇。又因为快指针速度是慢指针的两倍,所以相遇时必然只绕了一圈。
作者:知乎用户
链接:https://www.zhihu.com/question/23208893/answer/117115415
2.环路起始点在哪里。
将fast和slow的步进都设为1,这样 相遇点必然是链路入口,不然步长一样其他地方不会相遇(当然,此时fast和slow是相遇的,需要将其拉开,将fast重新指向头结点,如果slow此时也在这,那么头结点就是入口)。相遇点一定是回路入口,但是可能有人会担心,快慢指针是不是必然会相遇,有人也对此做了证明:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点p。https://www.cnblogs.com/songdechiu/p/6686520.html
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast,*slow;
fast=slow=head;
do
{
if(fast==NULL ||fast->next ==NULL )
return nullptr ;
fast=fast->next ->next ;
slow=slow->next ;
}while(fast!=slow);
fast=head;
while(fast!=slow)
{
fast=fast->next ;
slow=slow->next ;
}
return fast;
}
};