經典題目——鏈表中環的入口結點

鏈表中環的入口結點

引例:給定一個鏈表,若其中包含環,則輸出環的入口節點。若其中不包含環,則輸出null。

在這裏插入圖片描述

給定如上所示的鏈表:
[1, 2, 3, 4, 5, 6]
2
注意,這裏的2表示編號是2的節點,節點編號從0開始。所以編號是2的節點就是val等於3的節點。
則輸出環的入口節點3.


本題所用到的方法是快慢指針掃描。
圖1 循環鏈表示意圖
設i指針速度爲v,j指針速度爲2v,兩點在c點時第一次相遇。ab距離爲x,bc距離爲y,cb距離爲z。設n爲相遇時j所轉的圈數。則在相遇時:
j走過的路徑Sj = x + (y + z)*n + y;
i走過的路徑Si = x + y;
由速度可知,二者的路徑關係爲Sj = 2 * Si;
即x + (y + z)*n + y = 2 * (x + y),整理得
x = (n - 1)(y + z) + z;
由於n是任意整數,不妨設爲1,則x = z;
由此可知,j節點在c點再往前走x個長度即可到達b點。
爲了節省內存,我們讓i重新指向頭結點,i和j同時往前以相同速度移動,當兩者再次相遇時就找到了答案。
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *entryNodeOfLoop(ListNode *head) {
        auto i = head, j = head;//i是慢的, j是快的
        while(i && j){
            i = i -> next;
            j = j -> next;
            if(!j) return NULL;
            j = j -> next;
            if(i == j){
                i = head;
                while( i != j){
                    i = i -> next;
                    j = j -> next;
                }
                return i;
            }
        }
        return NULL;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章