題目:一個鏈表中包含環,請找出該鏈表的環的入口結點。
思路:
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;
}
};