【刷算法】判斷鏈表是否有環以及返回入環節點

題目描述

判斷一個單鏈表是否有環,有環則返回入環節點,不然返回nulloop

1->2->3->4->5->6
            ↑  ↓
            8<-7

例如上面這個鏈表就有環,入環節點是5ui

判斷鏈表有環

一般判斷鏈表是否有環,會採用快慢指針的方法,其實道理很簡單,就像兩我的賽跑且一我的跑得快一我的跑得慢。若是賽道是直的,那麼快人跑到終點時慢人還未到;若是賽道是環形,則快人和慢人總會相遇。
代碼實現this

function ListNode(x){
    this.val = x;
    this.next = null;
}
function EntryNodeOfLoop(pHead){
if(pHead === null)
    return null;
// 快慢指針從鏈表的頭部開始
var fast = pHead;
var slow = pHead;

while(fast.next !==null && fast.next.next !== null) {
// 快指針每次走兩步;慢指針每次走一步
    slow = slow.next;
    fast = fast.next.next;
    // 快慢指針相遇時,跳出while循環
    if(slow === fast)
        break;
}
// 快指針已經到了鏈表尾部了還沒和慢指針相遇,說明沒有環
if(fast === null || fast.next === null)
    return null;
    
// 後續會處理有環的狀況...
}

找到入環節點

常見的方法是:在肯定鏈表有環以後,慢指針從新指向鏈表頭,快指針留在相遇處;而後快慢指針再以每次移動1個節點的速度前進,最終他們在入環節點相遇。
爲何這麼作就能夠保證在入環節點相遇?證實一下:
圖片描述
如圖,設整個鏈表長度爲L,環長度爲R,且距離具備方向性,例如CB是C點到B點的距離,BC是B點到C點的距離,CB!=BC。當證實有環時,fast和slow都順時針到了B點,則此時:
slow走的距離:AC+CB
fast走的距離:AC+k*R+CB(k=0,1,2...)
因爲fast每次走2個節點,slow每次走1個節點,因此:
2(AC+CB) = AC+k*R+CB
AC+CB = k*R
AC+CB = (k-1)*R+R
AC = (k-1)*R+R-CB
AC = (k-1)*R+BC
從最終的表達式能夠看出來,AC的距離等於繞環若干圈後再加上BC的距離,也就是說慢指針從A點出發以速度1前進、快指針從B點出發以速度1前進,則慢指針到C點時,快指針也必然到了。
代碼實現:spa

function ListNode(x){
    this.val = x;
    this.next = null;
}
function EntryNodeOfLoop(pHead){
    if(pHead === null)
        return null;
    var fast = pHead;
    var slow = pHead;

    while(fast.next !==null && fast.next.next !== null) {
        slow = slow.next;
        fast = fast.next.next;
        if(slow === fast)
            break;
    }

    if(fast === null || fast.next === null)
        return null;
    // 有環,slow從新回到鏈表頭
    slow = pHead;
    
    // slow和fast從新相遇時,相遇節點就是入環節點
    while(slow !== fast) {
        slow = slow.next;
        fast = fast.next;
    }

    return slow;
}
相關文章
相關標籤/搜索