题目
给定一个链表的头节点head,返回链表开始入环的第一个节点。 如果链表无环,则返回null。
链接:142. 环形链表 II - 力扣(LeetCode)
题解
方法一:设置两个指针,一个指针指向链表头结点,一个指针指向判环时快慢指针相遇的位置,然后两个指针同时走,它们会在环的第一个结点处相遇。
判断链表是否有环:力扣141. 环形链表_啊哈leelee~的博客-CSDN博客
证明如下。
假设链表起始结点head到环起始结点head'的距离为L,环起始结点head'到快慢指针相遇结点meet的距离为X,环的长度为C,则meet到head'的距离为C-X。
在判环时,慢指针slow走的路径长度为L+X,快指针fast走的路径长度为L+nC+X(n>=1)。而fast所走路径长度是slow所走路径长度的2倍,即L+nC+X=2*(L+X),展开得L= nC-X,也就是L=(n-1)C+C-X。即一个指针从head开始走,一个指针从meet开始走,这两个指针一定会在环起始结点相遇。
注意,在slow进环之前,fast可能已经在环里走了n圈了;slow进环之后,fast一定会在一圈之内追上slow,因为slow和fast之间的距离最大是C,而slow和fast每移动一次,它们俩之间的距离就会减1,所以在slow移动一圈之前fast一定会追上。
代码如下:
struct ListNode *detectCycle(struct ListNode *head) { struct ListNode* slow = head; struct ListNode* fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; //寻找快慢指针相遇结点 if (slow == fast) { //寻找环起始结点 struct ListNode* meet = slow; while (head != meet) { head = head->next; meet = meet->next; } return meet; } } return NULL; }
方法二:设置一个指针meet指向快慢指针相遇的位置,设置一个指针meetNext指向meet的next,然后把meet的next置空,把问题转化为求解两个链表相交结点。如下图所示,问题转化为求解以head为头结点的链表和以meetNext为头结点的链表的相交结点。
求解链表相交结点:力扣160. 相交链表_啊哈leelee~的博客-CSDN博客
代码如下:
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) { tailA = tailA->next; lenA++; } while (tailB->next) { tailB = tailB->next; lenB++; } if (tailA != tailB) return NULL; struct ListNode* longList = headA; struct ListNode* shortList = headB; if (lenA < lenB) { longList = headB; shortList = headA; } int gap = abs(lenA - lenB); while (gap--) { longList = longList->next; } while (longList != shortList) { longList = longList->next; shortList = shortList->next; } return longList; } struct ListNode* detectCycle(struct ListNode* head) { struct ListNode* slow = head; struct ListNode* fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; //找到相遇结点 if (slow == fast) { struct ListNode* meet = slow; struct ListNode* meetNext = meet->next; meet->next = NULL; head = getIntersectionNode(head, meetNext); return head; } } return NULL; }