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

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

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
- 链表中节点的数目范围是 [0, 104]
- -10^5 <= Node.val <= 10^5
- pos 为 -1 或者链表中的一个 有效索引 。
- 你能用 O(1)(即,常量)内存解决此问题吗?
这题可采用快慢指针,其关键点还是该怎么去移动这两个指针?这一点要理清楚。慢指针针每次走一步,快指针每次走两步,如果相遇就说明有环,如果有一个为空说明没有环。然后在有环的基础上需要找出入环的第一个结点,这里就涉及到一些公式推导了。
解决方法1(个人想法):
快慢指针第一次相遇:
当快慢指针第一次相遇(fast==slow)时,可以分析此时fast和slow的移动步数关系:
(注:因为快慢指针之间存在速度差,且差值为1,当链表中存在环时,fast必然与slow相撞,可以画图理解一下)
快慢指针第二次相遇:
这里是解决问题的关键,根据之前第一次相遇的fast和slow的步数关系可知道链表头结点到环入口所需要的步数为a+k*b,DS=n*b,这里就可知道当slow指针再移动a步时,就能得到DS=a+n*b,刚好就到达了入口结点,证毕;
综上所述,只要当快慢指针第一次相遇后,只需要把slow再移动a步即可
时间复杂度: O(N),最坏情况为O(N)+O(N),因此总体为线性复杂度O(N)
空间复杂度: O(1)
红色部分代表快慢指针相撞。(注:本人不会做成流程动画,希望会的朋友可以私信我指点一二,说个软件名字也可以,谢谢)
第一次相遇:

第二次相遇:

每个代码块都写了注释,方便理解,代码还可以改进;
(根据个人想法编写)
public class Solution {public ListNode detectCycle(ListNode head) {ListNode slow = head, fast = head;while(fast != null && fast.next != null){slow = slow.next;fast = fast.next.next;// 第一次相遇if(slow == fast){fast = head;while(true){// 第二次相遇if(slow == fast) return slow;slow = slow.next;fast = fast.next;}}}return null;}
}
提交结果:

以上就是今天要讲的内容,做题的时候,就是奔着双指针的思路进行解决的,一开始就能写到相遇就说明有环,但没有考虑到相遇之后两个指针的步数关系,所以就卡了好几个小时,但是看了大佬们的题解思路,就豁然开朗了,所以就赶紧记录一下这时刻。