这篇文章最初发表在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
使用额外存储
用一个hashtable存储访问过的指针,若当前指针以前也被访问过,则为环入口点。指针
时间O(n),空间O(n)code
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; }
使用快慢两个指针,快的指针一次走两步,慢的一次一步。若无环,快的会走到链表末尾。如有环,则快的先进入环内循环走圈,直到慢的进入以后,每同时走一次,快的就接近慢的一步,最终快的确定会遇到慢的。
假设从链表到环入口点距离为K,环的长度为L。当慢的走到环入口点时,慢的前进了K,快的前进了2K,此时慢的距离快的K%L,快的距离快的L-K%L,再接着走L-K%L次,快的追上慢的,此时距离入口点L-K%L。也就是说,慢的再走K%L就又回到环入口点。htm
若是咱们在快慢指针相遇时,让快的回到起始点,再跟慢的一块儿走,每次一步,那么快的走K步到环入口点,慢的此时也走了K步,因为相遇时慢的距离入口点K%L,因此此时慢的也在入口点,快的和慢的相遇在入口点!leetcode
时间:O(n),空间O(1)get
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; }
同解法二,使用快慢两个指针,相遇时说明有环。如何找到环入口点呢?假如咱们知道环的长度,咱们能够设两个指针,让第一个指针先走环的长度这么多步,另外一个指针指向链表头,而后两个指针一块儿走,那么慢的指针走到环入口点时,快的正好走过环入口点以后又走了环的长度,第二次到达环入口点,两个指针相遇在入口点!
那么如何得到环的长度呢?在检测是否有环的那个步骤中,快慢两个指针在环中相遇以后,继续每次快的走两步,慢的走一步,那么当它们再次相遇时,慢的正好走过一个环的长度。每走一次,快的接近慢的一步,能够认为开始的时候快的距离慢的环的长度那么多步。
时间O(n),空间O(1)
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/