题目:一个链表中包含环,请找出该链表的环的入口结点。
思路:
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; } };