題目:鏈表中環的入口結點
題目描述
給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。
解題思路:
ps: 來自劍指 offer評論區
假設x爲環前面的路程(黑色路程),a爲環入口到相遇點的路程(藍色路程,假設順時針走), c爲環的長度(藍色+橙色路程)
當快慢指針相遇的時候:
此時慢指針走的路程爲Sslow = x + m * c + a
快指針走的路程爲Sfast = x + n * c + a
2 Sslow = Sfast
2 * ( x + m*c + a ) = (x + n *c + a)
從而可以推導出:
x = (n - 2 * m )*c - a
= (n - 2 *m -1 )*c + c - a
即環前面的路程 = 數個環的長度(爲可能爲0) + c - a
什麼是c - a?這是相遇點後,環後面部分的路程。(橙色路程)
所以,我們可以讓一個指針從起點A開始走,讓一個指針從相遇點B開始繼續往後走,
2個指針速度一樣,那麼,當從原點的指針走到環入口點的時候(此時剛好走了x)
從相遇點開始走的那個指針也一定剛好到達環入口點。
所以2者會相遇,且恰好相遇在環的入口點。
最後,判斷是否有環,且找環的算法複雜度爲:
時間複雜度:O(n)
空間複雜度:O(1)
代碼實現:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead){
//定義兩個快慢指針
ListNode slow=pHead;
ListNode fast=pHead;
//快指針一次走兩步,滿指針一次走一步,找到兩個鏈表的相遇節點
while(fast!=null && fast.next!=null) {
slow=slow.next;
fast=fast.next.next;
//兩者的相遇點
if(slow==fast) {
//使快慢指針中的其中一個頭節點
fast=pHead;
//找到換的入口節點
while(slow!=pHead) {
slow=slow.next;
pHead=pHead.next;
}
return slow;
}
}
//沒有相遇節點,即沒有環,返回null
return null;
}
}