題解-Linked List Cycle II

這篇文章最初發表在http://www.meetqun.com/thread-821-1-1.html ,此處略有改動。html

建議想要認真準備的同窗本身先嚐試,看完分析嘗試,而後把本身寫的代碼和我寫的對比,看看有哪些地方作得比我好(好比個人單行if語句不套大括號,可能對代碼修改的時候就不方便),哪些地方作得比我差(好比我用了fast,slow,而你用了沒意義的命名),多總結,多反思。面試中代碼寫得如何也是考察的重中之重,個人感受甚至比算法想沒想出來還重要,畢竟算法工做以後基本再也不須要,而面試官做爲你將來的同事,但是要常常review你的代碼的喲。總而言之,只是看水平是提高不了的。node

題目

Leetcode: https://oj.leetcode.com/problems/linked-list-cycle-ii/面試

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

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

解法一:

1.1 分析

使用額外存儲
用一個hashtable存儲訪問過的指針,若當前指針以前也被訪問過,則爲環入口點。指針

1.2 複雜度

時間O(n),空間O(n)code

1.3 代碼

ListNode *detectCycle(ListNode *head) {
    unordered_set<ListNode*> visited;
    while (head != nullptr) {
        if (visited.find(head) != visited.end()) 
                            return head;
        visited.insert(head);
        head = head->next;
    }
    return nullptr;
}

解法二:

2.1 分析

使用快慢兩個指針,快的指針一次走兩步,慢的一次一步。若無環,快的會走到鏈表末尾。如有環,則快的先進入環內循環走圈,直到慢的進入以後,每同時走一次,快的就接近慢的一步,最終快的確定會遇到慢的。
假設從鏈表到環入口點距離爲K,環的長度爲L。當慢的走到環入口點時,慢的前進了K,快的前進了2K,此時慢的距離快的K%L,快的距離快的L-K%L,再接着走L-K%L次,快的追上慢的,此時距離入口點L-K%L。也就是說,慢的再走K%L就又回到環入口點。htm

若是咱們在快慢指針相遇時,讓快的回到起始點,再跟慢的一塊兒走,每次一步,那麼快的走K步到環入口點,慢的此時也走了K步,因爲相遇時慢的距離入口點K%L,因此此時慢的也在入口點,快的和慢的相遇在入口點!leetcode

2.2 複雜度

時間:O(n),空間O(1)get

2.3 代碼

ListNode *detectCycle(ListNode *head) {
    ListNode* fast = head;
    ListNode* slow = head;
    while (fast != nullptr && fast->next != nullptr) {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow) break;
    }
    if (fast == nullptr || fast->next == nullptr)
        return nullptr;
    fast = head;
    while (slow != fast) {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

解法三:

3.1 分析

同解法二,使用快慢兩個指針,相遇時說明有環。如何找到環入口點呢?假如咱們知道環的長度,咱們能夠設兩個指針,讓第一個指針先走環的長度這麼多步,另外一個指針指向鏈表頭,而後兩個指針一塊兒走,那麼慢的指針走到環入口點時,快的正好走過環入口點以後又走了環的長度,第二次到達環入口點,兩個指針相遇在入口點!
那麼如何得到環的長度呢?在檢測是否有環的那個步驟中,快慢兩個指針在環中相遇以後,繼續每次快的走兩步,慢的走一步,那麼當它們再次相遇時,慢的正好走過一個環的長度。每走一次,快的接近慢的一步,能夠認爲開始的時候快的距離慢的環的長度那麼多步。

3.2 複雜度

時間O(n),空間O(1)

3.3 代碼

ListNode *detectCycle(ListNode *head) {
    ListNode* fast = head;
    ListNode* slow = head;
    while (fast != nullptr && fast->next != nullptr) {
        fast = fast->next->next;
        slow = slow->next;
        if (fast == slow) break;
    }
    if (fast == nullptr || fast->next == nullptr)
        return nullptr;
    int cycleLength = 0;
    do {
        slow = slow->next;
        fast = fast->next->next;
        ++cycleLength;
    } while (slow != fast);
    fast = slow = head;
    while (cycleLength > 0) {
        fast = fast->next;
        --cycleLength;
    }
    while (fast != slow) {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

相關題目

Linked List Cycle:
https://leetcode.com/problems/linked-list-cycle/

相關文章
相關標籤/搜索