题目描述
这道题显然是上一道题的一个进阶,上一道题是判断链表是否有环,这道题是求环的入口点
思路一:
①定义快慢指针,若链表带环,求出链表在环中的相遇点
②再定义一个指针meet,meet从快慢指针相遇点开始走,头指针head从链表的头开始走,两指针每次都走一步,两指针的相遇点即为链表入环口
思路合理性的证明:
思路一中的第一点上道题我们已经说明过了,下面是对思路一第二点的阐释
这里面有一个重要等式,就是 快指针走的路程 是 慢指针的两倍
以下过程为常见错误!!!
L + C + X = 2(L+X)
解得 L = C -X
因此meet和head相遇点即为入环点
错误原因:误认为快指针追上慢指针时只多走了一圈,但实际快指针在慢指针入环之前可能已经走了很多圈了
正确等式
L + n*C + X = 2(L+X)
n*C = L + X
L = n * C - X 这个式子说明了meet走n圈再倒退X(就是环的入口点) 就是L的距离,那head和meet不就在环的入口点相遇了吗?
上式还可以写成 L = (n-1)*C + C-X , 也就是meet指针走n-1圈再走 C - X ,也就来到了环的入口点
这就说明了思路一的正确性
完整代码
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode * fast = head;
struct ListNode * slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
{
struct ListNode* meet = fast;
while(meet != head)
{
head = head->next;
meet = meet->next;
}
return meet;
}
}
return NULL;
}
思路二:从fast与slow相遇的节点处断开,转化成之前讲过的求两个相交链表第一个公共节点的问题
完整代码
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
struct ListNode* tailA = headA;
struct ListNode* tailB = headB;
int lenA = 1, lenB = 1;
while (tailA->next)
{
tailA = tailA->next;
lenA++;
}
while (tailB->next)
{
tailB = tailB->next;
lenB++;
}
if (tailA != tailB)
{
return NULL;
}
//长的先走差距步
int gap = abs(lenA - lenB);
struct ListNode* longList = headA;
struct ListNode* shortList = headB;
if (lenA < lenB)
{
longList = headB;
shortList = headA;
}
while (gap--)
{
longList = longList->next;
}
while (longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return longList;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* fast = head;
struct ListNode* slow = head;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if(slow == fast)
{
struct ListNode* meet = fast;
struct ListNode* rhead = meet->next;
meet->next = NULL;
struct ListNode* result = getIntersectionNode(head, rhead);
return result;
}
}
return NULL;
}
本篇博客就介绍到此,欢迎大家交流指正~