鏈表中環的入口結點

牛客上看到這樣一道題:

題目描述

一個鏈表中包含環,請找出該鏈表的環的入口結點。


思路分析:

鏈表中有環的題目似乎也算是一個非常經典的面試筆試題了,也是很多人喜歡問到的, 這道題其實有很多思路

       思路一

我的第一反應是用map或者set,遍歷鏈表,把每一個節點映射到map中或者添加到set中,當要添加的節

        點在map或者set中已經存在的時候,就是我們要的入口節點了。  這種方法的缺點就是犧牲了空間

       思路二

既然有環,那麼我們自然會想到用兩個指針,一個走的快,一個走的慢,這樣肯定有重合的時候,這時候

快指針比慢指針多走了一個環

  • 第一步,找環中相匯點。分別用p1,p2指向鏈表頭部,p1每次走一步,p2每次走二步,直到p1==p2找到
  • 在環中的相匯點。
  • 第二步,找環的入口。接上步,當p1==p2時,p2所經過節點數爲2x,p1所經過節點數爲x,設環中有n個節點
  • ,p2比p1多走一圈有2x=n+x; n=x;可以看出p1實際走了一個環的步數,再讓p2指向鏈表頭部,p1位置不變,p1,
  • p2每次走一步直到p1==p2; 此時p1指向環的入口。
下面貼上兩種實現:
一:map實現,set一樣的思路
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL || pHead->next == NULL)
            return NULL;
		while(pHead != NULL){
            m[pHead]++;
            if(m[pHead] == 2)
                return pHead;
            pHead = pHead->next;
        }
        return NULL;
    }
private:
    map<ListNode*,int> m;
};


二:快慢指針實現
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if(pHead == NULL || pHead->next == NULL)
            return NULL;
        ListNode p1 = pHead;
        ListNode p2 = pHead;
        while(p2 != NULL && p2->next != NULL ){
            p1 = p1->next;
            p2 = p2->next->next;
            if(p1 == p2){
                p2 = pHead;
                while(p1 != p2){
                    p1 = p1->next;
                    p2 = p2->next;
                }
                if(p1 == p2)
                    return p1;
            }
        }
        return NULL;
    }
};





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章