题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
问题分析:设置两个指针,pSlow初始化为pHead,在后,走的慢;pFast初始化为pHead->next,在前,走的快,二者一定会在环内相遇;二者相遇之后设置计数器,令指针沿着环走一圈,计算环中元素数量;设置两个指针p1和p2,令p1先走环中元素数量的位置,然后两个同时走,二者会在环入口相遇
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if(pHead==NULL)return NULL;
//先计算环中结点的个数
//快慢指针相遇结点一定在环中
//每向前走一步,检验是否为空,避免链表不是环的时候,程序出错
ListNode *pSlow=pHead,*pFast=pHead->next;
while(pFast!=NULL&&pSlow!=NULL)
{
pSlow=pSlow->next;
pFast=pFast->next;
if(pFast==pSlow) break;
if(pFast!=NULL)
pFast=pFast->next;
}
//开始统计环结点数
int countNum=1;
ListNode *pTempNode=pFast->next;
if(pFast==pSlow&&pFast!=NULL)
{
while(pTempNode!=pFast)
{
pTempNode=pTempNode->next;
++countNum;
}
}
else
return NULL;
//再设两指针,一先一后
ListNode *p1=pHead,*p2=pHead;
for(int i=0;i<countNum;i++)
p1=p1->next;
while(p1!=p2)
{
p1=p1->next;
p2=p2->next;
}
return p1;
}
};
改进方法:
在 fast 和 slow 同时指向 pHead 时,当二者相遇时,直接令 fast 指向 pHead,二者同步向前走,相遇时就是环的入口。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
if(pHead == NULL)
return NULL;
ListNode* fast = pHead;
ListNode* slow = pHead;
while (fast != NULL && slow != NULL){
slow = slow->next;
if (fast->next != NULL)
fast = fast->next->next;
else
return NULL;
if (slow == fast)
break;
}
fast = pHead;
while(fast != slow){
fast = fast->next;
slow = slow->next;
}
return fast;
}
};