劍指Offer 面試題23:連結串列中環的入口節點 Java程式碼實現
阿新 • • 發佈:2019-02-12
題目描述
一個連結串列中包含環,請找出該連結串列的環的入口結點。 這題又用到了一快一慢兩個指標的方法,快指標一次走兩步慢指標一次走一步。可以證明,若存在環路,則這兩個指標一定會在環路中某個地方相遇。這也是檢測一個連結串列是否存在環路的方式。 接下來具體分析一下這兩個指標什麼時候會相遇。假設從第一個資料節點到環的入口節點需要走k步,那麼當慢指標slow走到環的入口節點時,快指標fast已經走了2k步,其中在環內走了k步。k可能會比環路的節點數大會很多,快指標應該距離環的入口節點mod(k,LOOP_SIZE)步,記為K。 也就是說:當slow走到入口節點時,fast在環內走了K步。slow落後於fast,相距K。或者說fast落後slow,相距(LOOP_SIZE-K)步。劍指Offer上的實現,有些許不同。上面的的分析比較全面,分析後代碼也更簡潔。Offer中的方法更好理解,但是程式碼量稍多一點。各有優點,大家自己斟酌。Offer中的實現思路如下: 1.通過一快一慢兩個指標找到碰撞處 2.遍歷環,得到環中的節點數N 3.兩個指標都初始指向第一個節點,然後第一個指標先走N步(兩個指標相距就是環內節點數),然後一起走,第一次相遇的點就是環的入口。public static ListNode entryNodeOfLoop2(ListNode head){ if(head==null||head.next==null) return null; ListNode slow=head.next,fast=head.next; //找到碰撞處 ,處於連結串列中LOOPSIZE-k步 while(fast!=null&&fast.next!=null){ slow=slow.next; fast=fast.next.next; if(fast==slow) break; } //錯誤檢查 沒有環路 if(fast==null||fast.next==null){ return null; } //發生碰撞後,再將slow指向連結串列第一個資料點,fast流在碰撞處 //同速度走,相碰的地方就是 環路起始處 slow=head.next; while(slow!=fast){ slow=slow.next; fast=fast.next; } return fast; }
public static ListNode meetingNode(ListNode head){
if(head==null||head.next==null)
return null;
ListNode slow=head.next,fast=head.next;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(fast==slow)
return fast;
}
return null;
}
public static ListNode entryNodeOfLoop(ListNode head){
ListNode meetingNode=meetingNode(head);
if(meetingNode==null) return null;
//求環節點數目
int loopCount=1;
ListNode pNode=meetingNode;
while(pNode.next!=meetingNode){
pNode=pNode.next;
loopCount++;
}
//從第一個資料節點開始移動loopCount次
pNode=head.next;
for(int i=0;i<loopCount;i++){
pNode=pNode.next;
}
//同時移動
ListNode pNode2=head.next;
while(pNode!=pNode2){
pNode=pNode.next;
pNode2=pNode2.next;
}
return pNode;
}