给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
一、哈希
我们遍历链表中的每个节点,并将它记录下来;一旦遇到了此前遍历过的节点,就可以判定链表中存在环。借助哈希表可以很方便地实现。
class Solution {
public:
ListNode* detectCycle(ListNode* head)
{
unordered_set<ListNode*> visited;
while (head != NULL)
{
if (visited.count(head))
{
return head;
}
visited.insert(head);
head = head->next;
}
return NULL;
}
};
双指针
算法流程:
设置两个指针,快指针fast,慢指针slow。
第一种结果:fast走过链表末端,说明链表无环,直接返回NULL
第二种结果,两指针在环中 第一次相遇。我们来分析步数关系:
设链表有x+y个节点。其中 链表头部到链表入口 有 x 个节点(不计链表入口节点), 链表环 有 y 个节点;设两指针分别走了 f,s 步,则有
f=2s (因为快指针走的每轮比慢指针多一步)
f=s+ny(双指针都走过 x 步,然后在环内绕圈直到重合,重合时快指针比慢指针多走环长度的整数倍,假定为n)
两式相减得f=2ny,s=ny,即f,s各自走了,2n,n个环的周长。
此时将快指针重新设置为指向头节点,s,f指针每轮向前走一步。
f=0,s=ny
当f=x时,s=ny+x,两指针重合,并同时指向链表环入口 。
class Solution {
public:
ListNode* detectCycle(ListNode* head)
{
ListNode* slow = head, * fast = head;
while (fast != NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
break;
}
if (fast == NULL || fast->next == NULL) return NULL;
ListNode* ptr = head;
while (ptr != slow)
{
ptr = ptr->next;
slow = slow->next;
}
return ptr;
}
};