题目
给定一个链表的头节点 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 解释:链表中没有环。
提示:
- 链表中节点的数目范围在范围
[0, 104]
内 -105 <= Node.val <= 105
pos
的值为-1
或者链表中的一个有效索引
思路
确定有无环
首先想,怎么才能确定有没有环。如果在日常生活之中,两个人绕着圈跑,如果一个人比另一个人跑得快,那么一定会相遇。
放在题目中同理,我们控制两个指针,一个每次走一步,一个每次走两步,如果指针相遇,那么就存在环,如果没相遇,就不存在。
找环的入口
图示:
可以看到,快指针每次走两步,慢指针一次走一步,快指针走的路程是慢指针的2倍。设快指针走了2k, 慢指针走了 k ,快指针就比慢指针多走了k 步,而这k 步中,快指针在环里转圈,也就是说k 是环的长度的整数倍。
此时,我们设环入口距相遇点的距离是 m,那么起点距环入口就是k - m, 相遇点距环入口的距离也是k - m,所以,只要我们把快慢指针中的任一个重新指向 head
,然后两个指针同速前进,k - m
步后一定会相遇,相遇之处就是环的起点了。
代码
public class Solution {
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null){
return null;
}
ListNode slow = head;
ListNode fast = head;
while(fast!=null&&fast.next!=null){
fast = fast.next.next;
slow = slow.next;
if(fast==slow) break;
}
if(fast==null||fast.next==null){
return null;
}
fast = head;
while(fast!=slow){
fast = fast.next;
slow = slow.next;
}
return fast;
}
}