LeetCode142:Linked List Cycle II

mickole發表於2014-02-17

題目:

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Follow up:
Can you solve it without using extra space?

解題思路:

判斷連結串列有無環,可用快慢指標進行,快指標每次走兩步,慢指標每次走一步,如果快指標追上了慢指標,則存在環,否則,快指標走到連結串列末尾即為NULL是也沒追上,則無環。

為什麼快慢指標可以判斷有無環?

因為快指標先進入環,在慢指標進入之後,如果把慢指標看作在前面,快指標在後面每次迴圈都向慢指標靠近1,所以一定會相遇,而不會出現快指標直接跳過慢指標的情況。

如何找到環的入口點呢?

我們先看圖再說話:

image

從圖各段我們分析,因為quick指標每次走兩步二slow指標每次走一步,所以當兩指標相遇時,quick走了兩倍的slow指標所走長度即:假設相遇點為z點

a + b + n * ( b + c ) = 2 * (a + b)  公式1

整理得:

a = n * (b + c) – b  公式2

根據公式2可知,要找到環入口點,可使用兩個指標,p1和p2,p1從連結串列頭開始走,p2從z點即快慢指標相遇點開始走,當p1指標走到Y(環入口點)時即長度為a時,p1走了n * (b + c) – b,可知p1也正好在Y點,所以利用p1和p2兩指標,當它們相遇時,相遇點即為環入口點。

實現程式碼:

#include <iostream>
using namespace std;

/**
Linked List Cycle II
 */
 
struct ListNode {
     int val;
     ListNode *next;
     ListNode(int x) : val(x), next(NULL) {}
};
void addNode(ListNode* &head, int val)
{
    ListNode *node = new ListNode(val);
    if(head == NULL)
    {
        head = node;
    }
    else
    {
        node->next = head;
        head = node;
    }
}
void printList(ListNode *head)
{
    while(head)
    {
        cout<<head->val<<" ";
        head = head->next;
    }
}

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == NULL || head->next == NULL)
            return NULL;
        ListNode *quick = head;
        ListNode *slow = head;
        while(quick && quick->next)//利用快慢指標判斷有無環 
        {
            quick = quick->next->next;
            slow = slow->next;
            if(quick == slow)
                break;
        }
        if(quick != slow)
            return NULL;
        //slow指標從頭開始走,quick指標從相遇點開始走,根據公式可知,相遇點即為環入口點 
        slow = head;
        while(slow != quick)
        {
            slow = slow->next;
            quick = quick->next;
        }
        return slow;                
    }
};
int main(void)
{
    ListNode *head = new ListNode(1);
    ListNode *node1 = new ListNode(2);
    ListNode *node2 = new ListNode(3);
    ListNode *node3 = new ListNode(4);
    head->next = node1;
    node1->next = node2;
    node2->next = node3;
    node3->next = node1;
    
    Solution solution;
    ListNode *rNode = solution.detectCycle(head);
    if(rNode)
        cout<<rNode->val<<endl;
    
    return 0;
}

相關文章