142. Linked List Cycle II

題目描述:給一個(gè)鏈表,判斷其中環(huán)的起始結(jié)點(diǎn),若沒(méi)有環(huán)則返回null。要求不改變鏈表,空間復(fù)雜度O(1)。

分析:這題與141題是同一個(gè)算法引出的一系列問(wèn)題,即Floyd判圈算法,又稱龜兔賽跑算法,可以在有限狀態(tài)機(jī)、迭代函數(shù)或者鏈表上判斷是否存在環(huán),并求出該環(huán)的起點(diǎn)與長(zhǎng)度的算法。

算法的核心思想是設(shè)置快慢指針,例如設(shè)fast指針的速度是slow指針的2倍,若兩指針能相遇則說(shuō)明有環(huán),否則無(wú)環(huán)。

例如有環(huán)鏈表如下圖:



算法可以解決的問(wèn)題有:

  1. 判斷鏈表中是否有環(huán),即141題。
  • 若就是一個(gè)循環(huán)鏈表,即Y點(diǎn)與X點(diǎn)是同一點(diǎn),鏈表的尾結(jié)點(diǎn)鏈到頭結(jié)點(diǎn),此時(shí)由于fast指針?biāo)俣仁莝low指針的2倍,故起點(diǎn)就是兩者相遇點(diǎn),每當(dāng)slow指針回到起點(diǎn)則相遇,因?yàn)閟low指針每走一圈即fast指針正好走兩圈。

  • 若是像上圖的一般情況,則當(dāng)slow指針到達(dá)Y處時(shí)fast指針已經(jīng)繞圈走了一段距離,故不一定會(huì)在Y處相遇。列方程可得這是一個(gè)只與時(shí)間有關(guān)的方程,即過(guò)一段時(shí)間一定可以相遇。

  • 若兩指針在fast走到末尾還未相遇,則說(shuō)明無(wú)環(huán)。

  1. 計(jì)算環(huán)的長(zhǎng)度。
  • 第一種方法:第一次相遇后,讓slow繼續(xù)走,記錄到下次遇到fast時(shí),即到達(dá)Z點(diǎn)時(shí),slow走過(guò)的結(jié)點(diǎn)數(shù)。此時(shí)slow走了一圈,正好還在Z點(diǎn)相遇。

  • 第二種方法:設(shè)環(huán)的長(zhǎng)度為L(zhǎng),第一次相遇時(shí)slow走過(guò)的距離:a+b,fast走過(guò)的距離:a+b+c+b。因?yàn)閒ast的速度是slow的兩倍,所以fast走的距離是slow的兩倍,有 2(a+b) = a+b+c+b,得到a=c。發(fā)現(xiàn)L=b+c=a+b,也就是說(shuō),從一開(kāi)始到二者第一次相遇,走過(guò)的結(jié)點(diǎn)數(shù)就等于環(huán)的長(zhǎng)度。

  1. 找到環(huán)中第一個(gè)節(jié)點(diǎn),即Y點(diǎn)。
    根據(jù)結(jié)論a=c,讓兩個(gè)指針?lè)謩e從X和Z開(kāi)始走,每次走一步,則正好會(huì)在Y相遇,也就是環(huán)的第一個(gè)節(jié)點(diǎn)。

  2. 將有環(huán)的鏈表變成單鏈表(解除環(huán))
    在上一個(gè)問(wèn)題的最后,將c段中Y點(diǎn)之前的結(jié)點(diǎn)與Y的鏈接切斷即可。

  3. 判斷兩個(gè)單鏈表是否有交點(diǎn),并找到第一個(gè)相交的結(jié)點(diǎn)。

  • 先判斷兩個(gè)鏈表是否有環(huán),如果一個(gè)有環(huán)一個(gè)沒(méi)環(huán),肯定不相交;如果兩個(gè)都沒(méi)有環(huán),則判斷兩個(gè)列表的尾部是否相等;如果兩個(gè)都有環(huán),判斷一個(gè)鏈表上的Z點(diǎn)是否在另一個(gè)鏈表上。

  • 分別計(jì)算兩個(gè)鏈表的長(zhǎng)度len1,len2,假設(shè)鏈表1較長(zhǎng),首先對(duì)較長(zhǎng)的鏈表遍歷len1 - len2個(gè)結(jié)點(diǎn)到結(jié)點(diǎn)p,此時(shí)結(jié)點(diǎn)p與鏈表2頭結(jié)點(diǎn)到兩者相交的結(jié)點(diǎn)的距離相同,在此時(shí)同時(shí)遍歷兩個(gè)鏈表,直到相遇的結(jié)點(diǎn)為止,這個(gè)結(jié)點(diǎn)就是相交的結(jié)點(diǎn)。

在slow指針入環(huán)后,在最多走一圈的時(shí)間內(nèi)必將遇到fast,時(shí)間復(fù)雜度O(n),空間O(1)。

代碼

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *slow = head, *fast = head;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if ( slow == fast)           //找到相遇點(diǎn)
            {
                ListNode *p = head;
                while( p != slow)            //slow從Z點(diǎn)出發(fā),新指針P從起點(diǎn)X出發(fā)同時(shí)走,直到相遇
                {
                    p = p->next;
                    slow = slow->next;
                }
                return p;
            }
        }
        return nullptr;
    }
};

參考:http://blog.csdn.net/sqiu_11/article/details/69841292

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容