【leetcode】Linked List Cycle II,判斷連結串列是否有環
阿新 • • 發佈:2019-02-08
本題意思是無修改的判斷一個連結串列是否具有環,並且返回環的初始節點,否則返回NULL。
一種方法是對已經訪問到的節點設定一些標誌,比如將next指標指向某一個特定節點,或者其他方法等。這樣的問題是會對連結串列進行修改。另一種方法是採用兩個指標在連結串列上滑動,一個指標每次只滑過一個節點,另一個指標每次滑過兩個節點,連個指標同時從起點開始滑動。可以證明,當存在環時,兩個指標會在某次相遇在同一個節點,否則,快的指標會先到達NULL。
針對本題,本文對兩種方法都實現了。第一種方法最後需要將next的修改又改回原來值。而第二種方法是在判斷具有環後正確找出環的初始節點。當兩個指標相遇後,固定一個指標不動,另一個指標繼續滑動,每次滑動一個節點並計數,當再次相遇時,可得到環具有的節點數n。然後使兩個指標指向頭結點,當其中一個指標先於另一個指標n個節點後同時同步(每次滑動一個節點)滑動。由於兩個指標距離等於環具有的節點數n,那麼他們必然在環初始節點處相遇,這樣就找到了環初始節點了。
程式碼如下:
//using inplace marks
ListNode* func(ListNode* head,ListNode* tag)
{
if(head==NULL)return NULL;
if(head->next == tag )
{
return head;
}
ListNode *p=head->next;
head->next = tag;
ListNode* ret=func(p,tag);
head-> next = p;
return ret;
}
ListNode *detectCycle(ListNode *head) {
ListNode* tag = new ListNode(0);
if(head==NULL)
{
return NULL;
}
ListNode* p = head->next;
head->next = tag;
ListNode* ret = func(p,tag);
head-> next = p;
return ret;
}
//using fast and slow pointers
ListNode *detectCycle(ListNode *head) {
ListNode *fast=head,*slow=head;
while(fast!=NULL&&slow!=NULL)
{
fast = fast->next;
if(fast == NULL) return NULL; //if doesn't has a cycle,then fast reach the end before the slow.
fast = fast->next;
slow = slow->next;
if(fast==slow) break;
}
if(fast!=NULL) // if has a cycle
{
int n=1; // n is the number of nodes in the cycle.
fast = fast->next;
while(fast!=slow)
{
++n;
fast=fast->next;
}
//Then we let two pointers begin from the front,and one begins after the another n nodes,
//so that they can meet at the node where cycle begins.
fast=head,slow=head;
while(n>0)
{
fast = fast->next;
--n;
}
while(fast!=slow)
{
fast=fast->next;
slow=slow->next;
}
return fast;
}
else
{
return NULL;
}
}