劍指offer學(xué)習(xí)筆記:8.3 鏈表

面試題56:鏈表中環(huán)的入口

一個鏈表中含環(huán)举反,如何找到環(huán)的入口
牛客網(wǎng)鏈接 https://www.nowcoder.com/practice/253d2c59ec3e4bc68da16833f79a38e4?tpId=13&&tqId=11208&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

/*
struct ListNode {
   int val;
   struct ListNode *next;
   ListNode(int x) :
       val(x), next(NULL) {
   }
};
*/
class Solution {
public:
   // 通過快慢指針判斷鏈表中是否存在環(huán)胆绊,如果存在環(huán),返回相遇節(jié)點(diǎn),如果不存在環(huán)赦役,返回NULL
   ListNode* meetNode(ListNode* pHead)
   {
       if (pHead == NULL)
       {
           return pHead;
       }
       ListNode* slow = pHead;
       ListNode* fast = slow->next;
       if (fast == NULL)
       {
           return NULL;
       }
       while(slow != NULL && fast != NULL && fast->next != NULL)
       {
           if (slow == fast)
           {
               return fast;
           }
           slow = slow->next;
           fast = fast->next->next;
       }
       return NULL;
   }
   ListNode* EntryNodeOfLoop(ListNode* pHead)
   {
       // 第一步:找到環(huán)中一個點(diǎn)
       ListNode* meet = meetNode(pHead);
       if (meet == NULL)
       {
           return NULL;
       }
       // 第二步:計算環(huán)的長度
       int n = 1;
       ListNode* tmp = meet->next;
       while(tmp != meet)
       {
           tmp = tmp->next;
           n++;
       }
       // 第三步:定義兩個指針想暗,指針p2先走n步
       ListNode* p1 = pHead;
       ListNode* p2 = pHead;
       for(int i = 0; i < n; i++)
       {
           p2 = p2->next;
       }
       // p1,p2再次相遇之處妇汗,就是環(huán)的入口
       while(p1 != p2)
       {
           p1 = p1->next;
           p2 = p2->next;
       }
       return p1;
   }
};

解題思路:
考慮沒有環(huán)的情況
思路1:雙指針法。
首先需要確認(rèn)環(huán)的長度说莫,當(dāng)確認(rèn)環(huán)的長度n后杨箭,讓指針p2先于指針p1走n步,當(dāng)兩個指針再次相遇储狭,相遇點(diǎn)即為環(huán)的入口互婿。
環(huán)的長度的尋找方法為,先找到環(huán)中一點(diǎn)辽狈,然后一邊往前一邊計數(shù)擒悬,當(dāng)再次走到此點(diǎn)時,即計數(shù)為環(huán)的長度稻艰。
環(huán)中一點(diǎn)尋找方法為快慢指針懂牧,同面試題15。若鏈表存在環(huán)尊勿,快慢指針一定相遇而且相遇與環(huán)中一點(diǎn)僧凤。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    // 通過快慢指針判斷鏈表中是否存在環(huán),如果存在環(huán)元扔,返回相遇節(jié)點(diǎn)躯保,如果不存在環(huán),返回NULL
    ListNode* meetNode(ListNode* pHead)
    {
        if (pHead == NULL)
        {
            return pHead;
        }
        ListNode* slow = pHead;
        ListNode* fast = slow->next;
        if (fast == NULL)
        {
            return NULL;
        }
        while(slow != NULL && fast != NULL && fast->next != NULL)
        {
            if (slow == fast)
            {
                return fast;
            }
            slow = slow->next;
            fast = fast->next->next;
        }
        return NULL;
    }
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        // 第一步:找到環(huán)中一個點(diǎn)
        ListNode* meet = meetNode(pHead);
        if (meet == NULL)
        {
            return NULL;
        }
        // 第二步:計算環(huán)的長度
        int n = 1;
        ListNode* tmp = meet->next;
        while(tmp != meet)
        {
            tmp = tmp->next;
            n++;
        }
        // 第三步:定義兩個指針澎语,指針p2先走n步
        ListNode* p1 = pHead;
        ListNode* p2 = pHead;
        for(int i = 0; i < n; i++)
        {
            p2 = p2->next;
        }
        // p1,p2再次相遇之處途事,就是環(huán)的入口
        while(p1 != p2)
        {
            p1 = p1->next;
            p2 = p2->next;
        }
        return p1;
    }
};

思路2:如果可以用額外內(nèi)存,其實(shí)把遍歷過的節(jié)點(diǎn)存在vector里擅羞,第一個被再次遍歷到的節(jié)點(diǎn)應(yīng)該就是入口

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/
class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        vector<ListNode*> list;
        while(pHead != NULL)
        {
            if (find(list.begin(), list.end(), pHead) == list.end())
            {
                list.push_back(pHead);
                pHead = pHead->next;
            }
            else {
                break;
            }
        }
        return pHead;
    }
};

面試題57:刪除鏈表中的重復(fù)節(jié)點(diǎn)

在一個被排序的鏈表中尸变,如何刪除重復(fù)的節(jié)點(diǎn)。注意不是刪除重復(fù)項(xiàng)减俏,而是如果節(jié)點(diǎn)有重復(fù)節(jié)點(diǎn)召烂,則將改節(jié)點(diǎn)和重復(fù)節(jié)點(diǎn)都刪除
leetcode鏈接 https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/

/**
* Definition for singly-linked list.
* struct ListNode {
*     int val;
*     ListNode *next;
*     ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
   ListNode* deleteDuplicates(ListNode* head) {
       if (head == NULL)
       {
           return NULL;
       }
       if (head->next == NULL)
       {
           return head;
       }
       ListNode* result = NULL;
       ListNode* pre = NULL;
       ListNode* cur = head;
       int begin = 1;
       while(cur != NULL)
       {
           bool needDelete = false;
           ListNode* next = cur->next;
           // cout << next->val << endl;
           // 只判斷當(dāng)前節(jié)點(diǎn)元素和下一個節(jié)點(diǎn)元素val是否相等,因?yàn)橹挥挟?dāng)節(jié)點(diǎn)值發(fā)生變化娃承,才會走到這里奏夫,所以當(dāng)前節(jié)點(diǎn)值和上一個節(jié)點(diǎn)一定不同
           if (next != NULL && cur->val == next->val)  
           {
               needDelete = true;
               // cout << "here" << endl;
           }
           if (!needDelete)
           {
               pre = cur;
               cur = cur->next;
               if (begin == 1)
               {
                   result = pre;
               }
               begin = 0;
           }  else
           {
               // 判斷當(dāng)前節(jié)點(diǎn)需要刪除怕篷,找到所有跟當(dāng)前節(jié)點(diǎn)值相同節(jié)點(diǎn),全部刪除
               int value = cur->val;
               ListNode* tmp = cur;
               while(tmp != NULL && tmp->val == value)
               {
                   next = tmp->next;
                   // delete tmp;    // 不能delete頭節(jié)點(diǎn)酗昼,會報錯
                   // tmp = NULL;
                   tmp = next;
               }
               if (pre == NULL)
               {
                   ;
               }
               else{
                   // cout << pre->val << endl;
                   pre->next = tmp;
               }
               cur = next;
               // cout << "here" << endl;
           }
       }
       return result;
   }
};

解題思路:
注意廊谓!因?yàn)轭^節(jié)點(diǎn)可能被刪除,因此當(dāng)前刪除函數(shù)應(yīng)該是delete(ListNode** pHead)而不是delete(ListNode* pHead)麻削≌舯裕或者用返回值作為新的鏈表頭。
因?yàn)殒湵硎桥判虻牡牛虼伺袛鄍->val和p->next->val即可电抚,不需要存在vector中惕稻。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竖共,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子俺祠,更是在濱河造成了極大的恐慌公给,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜘渣,死亡現(xiàn)場離奇詭異淌铐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蔫缸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門腿准,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拾碌,你說我怎么就攤上這事吐葱。” “怎么了校翔?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵弟跑,是天一觀的道長。 經(jīng)常有香客問我防症,道長孟辑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任蔫敲,我火速辦了婚禮饲嗽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奈嘿。我一直安慰自己喝噪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布指么。 她就那樣靜靜地躺著酝惧,像睡著了一般榴鼎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上晚唇,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天巫财,我揣著相機(jī)與錄音,去河邊找鬼哩陕。 笑死平项,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的悍及。 我是一名探鬼主播闽瓢,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼心赶!你這毒婦竟也來了扣讼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤缨叫,失蹤者是張志新(化名)和其女友劉穎椭符,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耻姥,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡销钝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了琐簇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒸健。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖婉商,靈堂內(nèi)的尸體忽然破棺而出似忧,到底是詐尸還是另有隱情,我是刑警寧澤据某,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布橡娄,位于F島的核電站,受9級特大地震影響癣籽,放射性物質(zhì)發(fā)生泄漏挽唉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一筷狼、第九天 我趴在偏房一處隱蔽的房頂上張望瓶籽。 院中可真熱鬧,春花似錦埂材、人聲如沸塑顺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽严拒。三九已至扬绪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間裤唠,已是汗流浹背挤牛。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留种蘸,地道東北人墓赴。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像航瞭,于是被迫代替她去往敵國和親诫硕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361