题解-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/

相关文章
相关标签/搜索