这道题的初级版本题目是这一道 传送门
解法一
思路:一个指针从相遇点开始走,一个指针从链表头开始走,他们会在环的入口点相遇。
推导过程
在追及相遇的过程中,慢指针走过的距离是 L+x,快指针走过的距离是 L+x+nc(n>=1)。
n是慢指针入环前,fast在环里走过的圈数。
所以有:
L+X+NC = 2 (L+X)
->> L=(n-1)C + (C-X)
所以再从meetnode到入口处和头结点到入口处长度相等。可以根据这条推论编程程序。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* meetNode(struct ListNode* head)
{
struct ListNode* fast, *slow;
fast = slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
return fast;
}
return NULL;
}
struct ListNode *detectCycle(struct ListNode *head) {
// 思路一:一个指针从头开始走,另一个指针从相遇点开始同时走
// 找到相遇点
struct ListNode* meetnode = meetNode(head);
if(meetnode == NULL)
return NULL;
struct ListNode* p1 = head, *p2 = meetnode;
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
解法二
解法二思路是从meetnode下一个结点打断链表,转化为链表相交问题。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* meetNode(struct ListNode* head)
{
struct ListNode* fast, *slow;
fast = slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
return fast;
}
return NULL;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* meetnode = meetNode(head);
if(meetnode == NULL)
return NULL;
// 思路二:相交链表
struct ListNode* p1 = head, *p2 = meetnode->next;
meetnode->next = NULL; // 断开两条链表
// 计算长度
int cnt1 = 0, cnt2 = 0;
struct ListNode* cur = p1;
while(cur)
{
cnt1++;
cur = cur->next;
}
cur = p2;
while(cur)
{
cnt2++;
cur = cur->next;
}
int gap = abs(cnt1 - cnt2);
struct ListNode* longlist = p1, *shortlist = p2;
if(cnt2 > cnt1)
{
longlist = p2;
shortlist = p1;
}
// 长链表先走
while(gap--)
{
longlist = longlist->next;
}
while(longlist && shortlist)
{
if(longlist == shortlist)
return longlist;
else
{
longlist = longlist->next;
shortlist = shortlist->next;
}
}
return NULL;
}
注意点
一定要 meetnode->next = NULL;
断开两条链表,否则会陷入死循环!