142. 环形链表 II
- 一、题目描述
- 二、示例
- 三、实现
- 3.1 方法1
- 3.2 方法2
 
142. 环形链表 II
一、题目描述
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
二、示例
示例1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
三、实现
3.1 方法1
假设:
链表头到环入口点距离 = L
环入口点到相遇点距离 = X
环的长度 = Cslow走的路程: L + X L + X L+X
fast走的路程: L + n ∗ C + X L + n*C + X L+n∗C+X
由于fast速度是slow的两倍,则有等式: 2 ∗ ( L + X ) = L + n ∗ C + X 2*(L+X) = L + n * C + X 2∗(L+X)=L+n∗C+X
解得: L = n ∗ C − X = ( n − 1 ) ∗ C + C − X L = n*C - X = (n-1)*C + C-X L=n∗C−X=(n−1)∗C+C−X因此从链表头到环入口点距离( L = ( n − 1 ) ∗ C + C − X L = (n-1)*C + C-X L=(n−1)∗C+C−X)和从相遇点到环入口点距离( C − X C-X C−X)相同,只是差了 ( n − 1 ) ∗ C (n-1)*C (n−1)∗C 也就是 n − 1 n-1 n−1 个环长。
由上可知,我们使用两个指针,一个指针从相遇点走,一个指针从链表头开始走,他们必定会在入口点相遇。
struct ListNode* detectCycle(struct ListNode* head) {
	struct ListNode* slow = head, * 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;
}
3.2 方法2
快慢指针在环中相遇,把相遇点变成原链表的尾结点,相遇点的下一个结点变为新链表的头结点,这样求环的入口点问题,就变成了找两个链表的交点问题了。
但这会时间超时:参考代码 【求两个链表的交点-getIntersectionNode】
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
	struct ListNode* tailA = headA;
	struct ListNode* tailB = headB;
	// 1.判断是否相交 通过查看两个链表的尾结点是否相同
	int lenA = 1, lenB = 1;
	while (tailA->next)
	{
		tailA = tailA->next;
		++lenA;
	}
	while (tailB->next)
	{
		tailB = tailB->next;
		++lenB;
	}
	if (tailA != tailB)
	{
		return NULL;
	}
	// 2.找交点,让长的链表先走 差距 步
	int gap = abs(lenA - lenB);
	struct ListNode* longList = headA;
	struct ListNode* shortList = headB;
	if (lenA < lenB)
	{
		longList = headB;
		shortList = headA;
	}
	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, * fast = head;
	while (fast && fast->next)
	{
		slow = slow->next;
		fast = fast->next->next;
		// 带环 在环中相遇
		if (slow == fast)
		{
			struct ListNode* meet = slow;
			
			return getIntersectionNode(head, meet->next);
		}
	}
	return NULL;
}



















