AcWing 34 鏈表中環的入口節點
題目
給定一個鏈表,若其中包含環,則輸出環的入口節點。
若其中不包含環,則輸出null
。
樣例
給定如上所示的鏈表:
[1, 2, 3, 4, 5, 6]
2
注意,這裏的2表示編號是2的節點,節點編號從0開始。所以編號是2的節點就是val等於3的節點。
則輸出環的入口節點3.
思路
這道題解法很巧妙,有一股數學的氣息,首先我們回憶一下怎麼確定一個鏈表中是否存在環
我們是使用快慢指針的方式來確定鏈表中是否存在環的,兩個指針one
和two
都從鏈表的head
出發,one
每次走一個節點,two
每次走兩個節點,如果鏈表存在環的情況下,兩個指針一定會在環中的某個位置相遇,否則如果two
走到了鏈表結尾,說明鏈表沒有環
那我們如何確定鏈表中環的入口節點呢?請看這張圖
首先,我們假設入口節點b
距離head
節點a
的距離爲x
,兩個指針相遇的點c
距離b
點的長度是y
,那麼,one
指針走到b
需要x
步,而此時two
指針已經走了2x
步,正在環中某處(假設鏈表存在環),而當one
再走y
步就會到達兩個指針相遇的c
點,再次期間,two
同樣會走2y
步,所以,在one
到達b
點時,two
實際距離b
點y
步,也就是說,這個環的長度爲x + y
,所以我們可以得到,當two
在c
點時,它距離b
點差x
步
通過這個結論,我們可以在兩個指針相遇時,讓one
指回頭節點,此時one
距離b
點差x
步,two
距離b
點也爲x
步,從這個時候開始,我們讓兩個指針每次走一個單位,當兩個指針再次相遇時,這個點就是b
點,代碼如下:
代碼
class Solution {
public:
ListNode *entryNodeOfLoop(ListNode *head) {
auto i = head, j = head;
while (i && j) {
i = i->next;
j = j->next;
if (j) {
j = j->next;
if (!j) return 0;
}
if (i == j) {
i = head;
while (i != j) {
i = i->next;
j = j->next;
}
return i;
}
}
return 0;
}
};