题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路
1、首先判断链表中是否有环。利用快慢指针,即快指针一次移动两步,慢指针一次移动一步,如果链表中有环,那么快慢指针迟早会相遇。所以以快慢指针是否会相遇为条件判断链表中是否有环。
2、如果有环,找环的入口点。如上图所示,起点为S,环的入口点为A,快慢指针的相遇结点为B,假设快慢指针在环中顺时针移动。其中SA的距离、AB的距离及BA的距离分别为x,y,z。设c=y+z为环的长度。则有:
快指针走过的路程:sFast=x+nc+y(n为快指针在环中以A为起点绕的整数倍的圈数)
慢指针走过的路程:sSlow=x+mc+y(m为慢指针在环中以A为起点绕的整数倍的圈数)
因为快指针一次移动两步,慢指针一次移动一步,所以快慢指针相遇时,快指针走过的路程是慢指针的两倍,即sFast=2*sSlow。将上面的两个式子带入到这个等式中,得:
x = (n-2m)c-y = (n-2m-1)c+c-y = (n-2m-1)c+z
即S到A的距离等于数倍的环长加B到A的距离,也就是说,如果设置两个指针p,q,p指向起点S,q指向相遇点B(第一步快慢指针相遇的点),两个指针同时前进且步长都是1,那么这两个指针最终会在入口点A相遇(p走到A,q走了(n-2m-1)倍的环长回到B,又从B走到了A)。
代码(c++)
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead==NULL||pHead->next==NULL||pHead->next->next==NULL) return NULL;
ListNode* pFast=pHead->next->next;
ListNode* pSlow=pHead->next;
while(pFast!=pSlow){
if(pFast->next!=NULL&&pFast->next->next!=NULL){
pFast=pFast->next->next;
pSlow=pSlow->next;
}
else return NULL;
}
pFast=pHead;
while(pFast!=pSlow){
pFast=pFast->next;
pSlow=pSlow->next;
}
return pFast;
}
};