题目描述;
Linked List Cycle
Given a linked list, determine if it has a cycle in it.
Follow up: Can you solve it without using extra space?
如何判断一个单链表中有环?
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?
如何找到环的第一个节点?
题目大致有这么几种解法:1、最朴素的使用两个指针a和b,双重遍历,遇到a==b则存在环,复杂度为O(n^2)
2、使用HashSet,每遍历到一个节点就将节点放进HashSet中,再判断next是否在HashSet中,复杂度为O(n),当然做不到题目要求的“solve it without using extra space”。
3、“龟兔赛跑”法。先附图:
X为链表起点,Y为环的起点,Z为相遇点
两个指针fast,slow同时进行遍历操作,假设fast遍历的步长(即速度)为f,slow的遍历步长为s,则当两指针第一次相遇时,fast套了slow一圈,则fast的路程为:a+b+(b+c),slow的路程为a+b,有(a+2b+c)/(a+b)=f / s,当t=2,s=1时,该式变为a+2b+c=2(a+b),则a=c。
由此产生了更简单的方法,fast与slow第一次相遇时,将fast重新拉回X点,两指针以1为步长继续遍历,第二次相遇时的节点即为Y点。
C++代码:
/**
* 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) {
ListNode *slow = head;
ListNode *fast = head;
do
{
if(!slow||!fast)
return NULL;
slow=slow->next;
fast=fast->next;
if(!fast)
return NULL;
else
fast=fast->next;
}while(slow!=fast);
slow=head;
while(slow!=fast)
{
fast=fast->next;
slow=slow->next;
}
return slow;
}
};