1. 程式人生 > >leetcode OJ 判斷單鏈表中是否有環

leetcode OJ 判斷單鏈表中是否有環

題目:判斷單鏈表中是否存在環

Binary Tree Preorder Traversal


單鏈表的結構體為:

struct NodeList
{
    int val;
    NodeList *next;
    NodeList(int x) : val(x),next(NULL){}
};

思路很簡單,就是搞兩個指標,初始值均指向連結串列頭,但是一個跑的快,一個跑的慢。如果連結串列中沒有環,兩個指標不會相遇,如果有環的話,則一定會相遇(慢的被套圈了)。

這裡我們定下快指標一次走兩步,慢指標一次走一步。由於快指標每次追慢指標一格,快慢指標間最大距離<環長(快指標剛過環入口,慢指標進來了),所以在慢指標第一次走完環長之前,快指標必然能追上它(此處為後面做鋪墊)。

判斷有否存在環的演算法,思路有了很簡單:

bool hasCircle(NodeList *head)
{
    NodeList *fast=head;
    NodeList *slow=head;
    while(fast!=NULL&&fast->!=NULL)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow) return true;
    }
    return true;
}

看了看大牛寫的題目擴充套件,一般還要求找出環入口的位置,

思路是這樣的:

假設相遇時慢指標走了s,則快指標走了2s,兩者的差s必然為環長的n倍,即s=nl(l為環長),即如果一個指標S1從連結串列頭出發,另一個指標S2從相遇點出發(兩者速度相同),S1走到S2出發點時兩者一定會相遇(兩者都走了nl),而他們的速度是一樣的,說明他們在環入口處其實就相遇了,而且是第一次相遇(就在一起了~~~~),這樣我們就能定位到環入口了。

有了思路程式碼也很簡單(環已經存在):

NodeList* findCircleEnter(NodeList* head)
{
    NodeList *fast=head;
    NodeList *slow=head;
    while(fast!=NULL&&fast->!=NULL)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow) break;
    }
    slow=head;
    while(slow!=head)
    {
        slow=slow->next;
        fast=fast->next;
    }
    return slow;
}
另外,大牛還引申了“如何判斷兩個無環單鏈表是否相交”:運用判斷單鏈表環的想法,將其中一個連結串列首尾相連,然後判斷另一個是否有環,若有環則說明兩連結串列相交。

附上鍊接:

http://www.cppblog.com/humanchao/archive/2012/11/12/47357.html