题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意,pos 仅仅是用于标识环的情况,并不会作为参数传递到函数中。
说明:不允许修改给定的链表。
进阶:
你是否可以使用 O(1) 空间解决此题?
示例
提示
- 链表中节点的数目范围在范围 [0, 104] 内
- -105 <= Node.val <= 105
- pos 的值为 -1 或者链表中的一个有效索引
思路
使用快慢指针解决了这个问题,就是一个指针一次跳两个另一个跳一个,这两个指针首先走完了没有进入环的一部分,进入环后走了一段距离再相遇(也有可能第一次相遇就是环的头部,但是为了保险起见还是说走了一段距离后相遇吧)。我们可以设环前跳了a个,进入环后跳了b个后相遇,离环的起点还有c个距离。又因为fast指针走过的路是slow的2倍所以就有下面的式子:
2 (a + b) = a + b + n (b + c)
因为要求的是环的头,所以就得求a的值,化简后得:
a = n (b + c) - b
后面从n (b + c)
中提出一个b + c
就得:
a = (n-1)(b+c) + c
那么从上述式子中我们可以得出一个结论就是:如果有一个指针从头节点以每次跳一个的速度走那么就会和slow遇上了。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head, *slow = head;
while (fast) {
slow = slow->next;
if (fast->next == nullptr) {
return nullptr;
}
fast = fast->next->next;
if (fast == slow) {
ListNode* ans = head;
while (ans != slow) {
ans = ans->next;
slow = slow->next;
}
return ans;
}
}
return nullptr;
}
};