https://leetcode-cn.com/problems/linked-list-cycle-ii/
分析
这道题在第141题环形链表的基础上,不仅要求判断链表是否有环,还要求在有环的情况下给出入环的节点。如果用哈希表的话,自然与第141题解法相同,但那并不是这种题目的本意。单纯用双指针,只能判断是否有环,但快慢指针的相遇点并不一定在入环处,需要巧妙地改进双指针的解法来完成本题。
解法、双指针
链表无环时自不必说,当链表有环时,我们分两个阶段来解决这个问题:
阶段1:寻找相遇点
假设链表长a+b,环外长度a,环内长度b。
- fast走过的步数始终是slow的2倍,因此
f = 2s
- 当fast与slow相遇时,fast一定比slow多走了n个环的长度,即
f = s + nb
由以上得f = 2nb
,s = nb
阶段2:寻找入环点
从链表头部出发,slow指针走到入环点所有需要的步数是a + nb
,而此时slow已经走了nb
步,所以只需再走a步就可以到达入环点。
如何控制slow再走a步?我们再设置一个指针指向链表头部,它与slow同步移动,它们会在走过a步时在入环点相遇。
代码
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head, *slow = head;
ListNode *meet = nullptr;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) {
meet = fast;
break;
}
}
if (!meet) return nullptr;
while (head != meet) {
head = head->next;
meet = meet->next;
}
return head;
}
};
复杂度分析
当链表中无环时,快指针移动 n / 2 n/2 n/2次到达链表尾部,时间复杂度 O ( n ) O(n) O(n);当链表中有环时,阶段1slow指针一般不会走多个环,阶段2slow指针移动a步,所以时间复杂度 O ( n ) O(n) O(n)。空间复杂度 O ( n ) O(n) O(n)。