142 Linked List Cycle II [Leetcode]

題目內容:

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?

解題思路:
1) 通過一快一慢兩個指針,我們可以很方便得檢測鏈表中有沒有環,只需不停向前直到兩個指針相遇即可。

到達相遇位置後,若讓單步走的指針再繞環一圈回到原點,就可以知道環的長度。這時,如果我們讓其中一個指針先走環的長度,另一個指針從原點出發,那麼他們之後相遇時的位置就是環的入口處。
代碼:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == NULL || head->next == NULL)
            return NULL;

        ListNode *one = head->next, *two = one->next;

        // check whether there is a cycle in list
        while(two != NULL && one != two) {
            one = one->next;
            two = two->next;
            if(two == NULL)
                break;
            two = two->next;
        }
        if(two == NULL)
            return NULL;

        // get the length of cycle - clength
        int clength(1);
        one = one->next;
        while(one != two) {
            one = one->next;
            ++clength;
        }

        ListNode *p = head;
        one = head;
        for(int i = 0; i < clength; ++i)
            p = p->next;
        while(p != one) {
            p = p->next;
            one = one->next;
        }

        return p;
    }
};

2) 深入分析一下指針在查找環過程中的相遇點:

設鏈表開始處距離環入口處的距離爲k,環的長度爲c。

當慢指針到達入口處時,它走了k步,而快指針此時已經在環內,一共走了2k步,設此時它距離環的入口n步。那麼還需要c-n步,快指針就會和慢指針相遇(快指針每次都趕上慢指針一步)。相遇時的位置就是c-n(慢指針是從環的入口處出發的)。

再考察k與c、n之間的關係。快指針在圈內從起點開始行走了k步到達了n的位置,那麼它們之間的關係滿足:k=cx+n ,x爲自然數。

如果從相遇時的位置開始,讓慢指針再走cx+n 步,就會又回到入口處的節點。顯然k滿足條件。因此我們重新設置一個指針指向起始節點,讓起始節點的指針和環中慢節點的指針同時向前走k步,這兩個指針必然在環的入口處相遇。

實現代碼:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        if(head == NULL || head->next == NULL)
            return NULL;

        ListNode *one = head->next, *two = one->next;

        // check whether there is a cycle in list
        while(two != NULL && one != two) {
            one = one->next;
            two = two->next;
            if(two == NULL)
                break;
            two = two->next;
        }
        if(two == NULL)
            return NULL;

        ListNode *p = head;
        while(p != one) {
            p = p->next;
            one = one->next;
        }

        return p;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章