题目:一个链表中包含环,请找出该链表的环的入口结点。
思路:
1、确定一个链表中是否包含环。可以定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步,如果走的快的指针追上了走的慢的指针,那么链表就包含环;如果走的快的指针走到了链表的末尾,都没有追上第一个指针,那么链表就不包含环。
2、如何找到环的入口。分两步进行:(1)判断环中节点的数目;(2)找到环的入口。
(1)判断环中节点的数目。在判断一个链表里是否有环时用到了一快一慢的两个指针,如果两个指针相遇,则表明链表中存在环,所以两个指针相遇的节点一定是在环中!可以从这个相遇的节点出发,直到又回到这个节点,就可以得到环中节点数了。
(2)找到环的入口。如果链表中的环有n个节点,则指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口节点时,第一个指针已经围绕着环走了一圈,又回到了入口节点。
函数MeetingNode在链表存在环的前提下找到一快一慢两个指针相遇的节点,函数EntryNodeOfLoop用来找环的入口节点。
class Solution {
private:
ListNode* MeetingNode(ListNode* pHead){
if(pHead == nullptr){
return nullptr;
}
ListNode* pSlow = pHead->next;
if(pSlow == nullptr){
return nullptr;
}
ListNode* pFast = pSlow->next;
while(pFast != nullptr && pSlow != nullptr){
if(pFast == pSlow){
return pFast;
}
pSlow = pSlow->next;
pFast = pFast->next;
if(pFast != nullptr){
pFast = pFast->next;
}
}
return nullptr;
}
public:
ListNode* EntryNodeOfLoop(ListNode* pHead){
ListNode* meetingNode = MeetingNode(pHead);
if(meetingNode == nullptr){
return nullptr;
}
int nodesInLoop = 1;
ListNode* pNode1 = meetingNode;
while(pNode1->next != meetingNode){
pNode1 = pNode1->next;
nodesInLoop++;
}
pNode1 = pHead;
for(int i=0;i<nodesInLoop;i++){
pNode1 = pNode1->next;
}
ListNode* pNode2 = pHead;
while(pNode1 != pNode2){
pNode1=pNode1->next;
pNode2=pNode2->next;
}
return pNode1;
}
};