题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
思路
判断一个链表是否有环并且找到环的开始位置.要求空间复杂度O(1)
和之前普通判断是否有环的思路是类似的, 依然是使用两个指针, 一快一慢, 快指针每次走两步慢指针每次走一步. 若两指针相遇了肯定有环否则遇到NULL则没环.
那么当有环时如何判断环的起始位置呢?
我们假设两指针走了k次后相遇, 链表头到环开始节点距离为S(即所求), 从环开始节点到两指针相遇节点距离为M, 环的长度为R;
则我们有:
- 快指针走的路程2k = S + M + xR, 其中x是快指针走过环的整圈数;
- 慢指针走的路程为k = S + M + yR, 其中y是慢指针走过环的整圈数;
则我们有S + M + xR = 2(S + M + yR), 化简得S + M = (x-y)R. 即我们得到了一个重要的结论:
从表头到相遇节点的距离等于环长的整数倍. 那么我们如果使用两个指针分别从表头和相遇节点开始向后每次走一步, 那么这两个节点走了S步后一定会相遇, 这个相遇节点即所求.
c++
/**
* 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 && fast->next){
fast = fast->next->next;
slow = slow->next;
if(slow == fast){
ListNode *slow2 = head;
while(slow2 != slow){
slow2 = slow2->next;
slow = slow->next;
}
return slow2;
}
}
return nullptr;
}
};