1°题目链接
2°思路
思路1(结论):
如何求环的入口点
结论:
一个指针从相遇点开始走
一个指针从链表头开始走
他们会在环的入口点相遇证明:
环之前的距离是L
slow在环中走过的距离为X
环的长度是C
追上相遇的过程中
慢指针走的距离:L+X
快指针走的距离:L+N*C+X(N>=1)
(N为相遇之前fast在环中走的圈数)
慢指针不可能在环中走过超过1圈
慢指针如果走了一圈
快指针已经走了两圈了 肯定追上了
快指针走的路程是慢指针的2倍
2(L+X)=L+N*C+X
L+X=N*C
L=N*C-X
L=(N-1)*C+C-X
相遇的节点设为meetNode
(N-1)*C相当于从meetNode走回到meetNode
C-X就是meetNode到相交点的距离
L就是head走到相交点的距离
相当于head和一个从meetNode开始走的
相等的时候就是相交点
思路2:
meetNode下一个作为头list指针
list和head遍历
当两个相交处就为环的入口处
转换成相交问题相交问题可见:
数据结构与算法 OJ练习第13篇
3°实现
思路1(结论):
struct ListNode* detectCycle(struct ListNode* head)
{
struct ListNode* slow = head, * fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
//相遇
struct ListNode* meet = slow;
//公式证明
while (meet != head)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
思路2:
//相交函数
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB)
{
struct ListNode* tailA = headA;
struct ListNode* tailB = headB;
int lenA = 1;
int lenB = 1;
while (tailA->next)
{
lenA++;
tailA = tailA->next;
}
while (tailB->next)
{
lenB++;
tailB = tailB->next;
}
int gap = abs(lenA - lenB);
struct ListNode* longlist = headA;
struct ListNode* lesslist = headB;
if (lenB > lenA)
{
longlist = headB;
lesslist = headA;
}
while (gap--)
{
longlist = longlist->next;
}
while (longlist != lesslist)
{
longlist = longlist->next;
lesslist = lesslist->next;
}
if (longlist == lesslist)
return longlist;
else
return NULL;
}
struct ListNode* detectCycle(struct ListNode* head)
{
struct ListNode* slow = head, * fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
//相遇
struct ListNode* meet = slow;
struct ListNode* list = meet->next;
meet->next = NULL;
struct ListNode* intersect=getIntersectionNode(head,list);
return intersect;
}
}
return NULL;
}
4°运行结果
#15环形链表 II#完