题目链接:https://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
.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?
思路:本题可以使用快慢指针来解决,快指针一次走两步,慢指针一次走一步。有两个步骤:
1.先找出是否有环及其快慢指针相遇的位置。
2.然后再找出环的入口
先来看第一个怎么解决:
快慢指针初始都在头部,设链表长度为n。
1.假如没有环,那么快指针最终会指向空指针。
2.如果有环,那么慢指针最多走n步(即回到头部)就会和快指针相遇。
如果快慢指针最终相遇了,就说明有环。那么如果找出环的入口位置呢?盗个图(自己也画了一个,嫌太丑)
假如从链表头到环入口长度为k(即D位置),快慢指针相遇在E,从相遇的节点到环入口长度为y。在相遇的时候快指针多走了一圈环形,那么快慢指针到相遇的时候各走的步数为:
slow = k + x;
fast = k + x + y + x;
因为快指针速度比慢指针快一倍,因此有如下关系:fast = 2 * slow,即:(k + x + y +x) = 2 * (k + x),可以得出 k = y。因此现在从快慢指针相遇的地方到环入口和从链表头到环入口的距离相等,所以让快慢指针以相同的速度从这两个地方再开始走,到相遇的地方即环的入口。
代码如下:
/**
* 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 || !head->next) return NULL;
ListNode *slow = head->next, *fast = head->next->next;
while(slow!=fast && fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
if(slow != fast) return NULL;
fast = head;
while(fast!=slow)
fast = fast->next, slow = slow->next;
return slow;
}
};