经典的链表题目。
1. 用双指针法判断是否有环
2. 将一个指针重置为链表首部,另一个指针保留在之前重合的位置,两个指针同时移动,相遇位置即为环出现的位置
2的证明:
设链表头节点是A,环出现位置为B,快慢指针最终相遇位置为C,如下图所示
设环的周长为p,则有:
1. 快指针所走的路径长度为 L_fast = AB + BC + np,其中n是整数
2. 慢指针所走的路径长度为 L_slow = AB + BC,因为慢指针在环里最多走了一圈
3. 因为快指针比慢指针的速度快一倍,所以 L_fast = 2 * L_slow
三式联立,化简得:
AB + BC = np
等价转化:AB = np - BC = (n - 1)p + (p - BC) = (n-1)p + CB
即AB - CB = mp,其中m是整数
所以,让两个指针分别从A和C出发,当其中一个指针走到B的位置时,另一个指针距离B的位置恰好是环长度的整数倍,因此最终他们在换上相遇的位置一定还在B
代码:
1 ListNode *detectCycle(ListNode *head) { 2 ListNode *fast = head; 3 ListNode *slow = head; 4 bool running = false; 5 6 while (fast && fast->next) { 7 if (fast == slow && running) 8 break; 9 running = true; 10 fast = fast->next->next; 11 slow = slow->next; 12 } 13 14 if (!fast || !fast->next) 15 return NULL; 16 17 fast = head; 18 while (fast != slow) { 19 fast = fast->next; 20 slow = slow->next; 21 } 22 23 return fast; 24 }