题目描述
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0
开始)。 如果 pos
是 -1
,则在该链表中没有环。
说明:不允许修改给定的链表。
样例
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。
输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。
进阶:
你是否可以不用额外空间解决此题?
算法分析
通过 LeetCode 141. 环形链表 的题解可以判断出环形链表是否存在环,而这题是需要找出 pos 的位置
fast 指针从原点每次走 2 步, slow 指针从原点每次走 1 步
1、当链表不存在环,fast 指针一定会事先走到 null,则 pos=−1
2、当链表中存在环时,如图所示,A 点是起点,B 点是入口,C 点是两个指针的第一次相遇点,假设 A 到 B 长度是 x, B 到 C 长度是 y,C 到 B 长度是 z,假设当 slow 指针走到 B 点时,fast 指针走到 C 点,fast 指针在环内兜了 n 圈,则由于 fast 走过的路程是 slow 的 2 倍,因此在第一次相遇时,slow 走过的路程是 x+y,fast 走过的路程是x+(y+z)∗n+y,因此 x+(y+z)∗n+y=2(x+y),由于 y+z 为环形的一圈,尽量凑在一起,因此化简为 x=(y+z)∗(n−1)+z
3、又化简后的等式可知,x 与 z 只相差圈数,因此从 C 点走 x 步一定会到达 B 点,等价于从 A 点走到 B 点,因此 fast 指针从 C 点每次走 1 步,slow 指针从原点每次走 1 步,当他们一定会在 B 点相遇并各自走了 x 步
时间复杂度 O(n)
时间复杂度分析:first 总共走了 2x+y 步,second 总共走了 2x+2y+x 步,所以两个指针总共走了 5x+3y 步。由于当第一次 first 走到 b 点时,second 最多追一圈即可追上 first,所以 y 小于环的长度,所以 x+y 小于等于链表总长度。所以总时间复杂度是 O(n)。
参考y总的hh
Java 代码
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head == null || head.next == null) return null;
ListNode fast = head.next;
ListNode slow = head;
while(fast != null)
{
if(fast == slow)
{
fast = fast.next;
slow = head;
while(fast != slow)
{
fast = fast.next;
slow = slow.next;
}
return slow;
}
fast = fast.next;
if(fast != null) fast = fast.next;
slow = slow.next;
}
return null;
}
}