JZ23 鏈表中環的入口結點 描述 給一個長度為n鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,返回null。 解析 環很大 在前面我們提到過快慢指針,判斷是否有環。如果有環,在來找環的入口。如果沒環直接返回null即可,我們假設是有環的,那麼會有兩種情況,一種是O型,一種是6型,其實原理都 ...
JZ23 鏈表中環的入口結點
描述
給一個長度為n鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,返回null。
解析
環很大
在前面我們提到過快慢指針,判斷是否有環。如果有環,在來找環的入口。如果沒環直接返回null即可,我們假設是有環的,那麼會有兩種情況,一種是O型,一種是6型,其實原理都一樣,這裡主要看一下6字型的環,他會有兩種情況,
如果有環,那麼快指針走過的路徑就是圖中a+b+c+b,慢指針走過的路徑就是圖中a+b,因為在相同的時間內,快指針走過的路徑是慢指針的2倍,所以這裡有a+b+c+b=2*(a+b),整理得到a=c
在相遇的時候再使用兩個指針,一個從鏈表起始點開始,一個從相遇點開始,每次他們都走一步,直到再次相遇,那麼這個相遇點就是環的入口。
環很小
這種情況下當快慢指針在環上相遇的時候,快指針有可能在環上轉了好幾圈,我們假設相遇的時候快指針已經在環上轉了n圈。
那麼相遇的時候快指針走過的路徑就是a+b+(b+c)*n,(b+c其實就是環的長度),慢指針走過的路徑是a+b。由於相同時間內快指針走過的路徑是慢指針的2倍。
所以有a+b+(b+c)n=2(a+b),整理得到a+b=n*(b+c),也就是說a+b等於n個環的長度。
我們還可以使用兩個指針,一個從鏈表的起點開始,一個從相遇點開始,那麼就會出現一種情況就是,一個指針在路徑a上走,一個指針一直在環上轉圈,最終會走到第一種情況。
代碼
package mid.JZ23鏈表中環的入口結點;
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode slow = hasCycle(pHead);
if (slow == null) return null;
//快的回到起點
ListNode fast = pHead;
while(fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
/**
* 判斷鏈表是否有環
* @param head
* @return
*/
public ListNode hasCycle(ListNode head) {
if (head == null) return null;
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null) {
//快的走兩步
fast = fast.next.next;
//慢的走一步
slow = slow.next;
//如果相同返回慢的指針
if (fast == slow) return slow;
}
return null;
}
}