數據結構面試 之 單鏈表是否有環及環入口點 附有最詳細明瞭的圖解

1.限制與要求

  • 不容許修改鏈表結構。算法

  • 時間複雜度O(n),空間複雜度O(1)。spa

2.思考

2.1判斷是否有環

若是鏈表有環,那麼在遍歷鏈表時則會陷入死循環,利用這個特徵,咱們能夠設計這樣的算法。設計

  • 使用一個slow指針,一個fast指針。指針

  • slow指針一次日後遍歷以1個節點,fast指針一次日後遍歷2個節點,一直作這樣的操做。code

  • 若是fast指針在遍歷過程當中,遍歷到了NULL節點說明鏈表沒有環。ip

  • 不然當slow指針和falst指針相同,則說明環有節點。leetcode

2.2環的入口節點

咱們假定鏈表頭到環入口的距離是len,環入口到slow和fast交匯點的距離爲x,環的長度爲R。slow和fast第一次交匯時,設slow走的長度爲:d = len + x,而fast走的長度爲:2d = len + nR + x,(n >= 1),從而咱們能夠得知:2len + 2x = len + nR + x,即len = nR - x,(n >= 1),因而咱們能夠獲得這樣的算法。rem

  • 使用一個cur指針指向鏈表頭節點,一個inter指針指向第一次的交匯點。get

  • cur指針和inter指針一塊兒日後遍歷。it

  • cur指針和inter指針相等時,cur和inter指針指向的就是環的入口節點。


inter指針在遍歷過程當中可能屢次(n >= 1)通過環入口節點,但當cur指針第一次達到入口節點時,inter指針此時必然也指向入口節點。

3.代碼實現

/**
 * 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 (NULL == head) return NULL;
        ListNode * fast = head;
        ListNode * slow = head;
        
        while (1)
        {
            fast = fast->next ? fast->next : NULL;
            if (NULL == fast) break;
            
            fast = fast->next ? fast->next : NULL;
            if (NULL == fast) break;
            
            slow = slow->next;
    
            if (slow == fast) break;
        }
        
        if (NULL == fast) return NULL;
        
        ListNode * cur = head;
        ListNode * inter = slow;
        
        while (cur != inter)
        {
            cur = cur->next;
            inter = inter->next;
        }
        
        return cur;
    }
};

4.OJ練習

LeetCode 單鏈表是否有環及入口

相關文章
相關標籤/搜索