一、题目要求
给定一个链表的头节点 head
,返回链表开始入环的第一个节点。 如果链表无环,则返回 null
。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos
是 -1
,则在该链表中没有环。注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
二、初步解法
2.1 初步思想
同leetcode141环形链表相同原理,使用hashMap存储结点,随后遍历链表,第一个与hashMap中结点key重复的结点就是入环点。
2.2 代码实现
public class Solution {
public ListNode detectCycle(ListNode head) {
Map<ListNode,Integer> map=new HashMap<>();
while(head!=null) {
if(map.get(head) == null) {
map.put(head,0);
head = head.next;
}
else {
return head;
}
}
return null;
}
}
2.3 运行结果
空间复杂度O(N),时间复杂度O(N)。
三、优化解法
3.1 算法思想
同leetcode141环形链表相同原理,使用快慢指针,快指针fastPtr一次走两步,慢指针slowPtr一次走一步。当二者第一次相遇之后,将慢指针置于头节点,随后快指针和满指针都一次只走一步,再次相遇的位置就是入环点。
原理:设第一次相遇时慢指针走的步数为x,快指针走的步数2x,二者相差为x,快指针在环中追赶慢指针(直至超过一圈),额外走了x步,距离完成下一圈的步数为头结点到“起跑线”的距离。
快慢指针第二次相遇的时候,快指针已经再次完成了一圈,故二者相遇处为入环点。
3.2 代码实现
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slowPtr = head;
ListNode fastPtr = head;
//如果为只有一个结点的环,直接返回
if(fastPtr!=null) {
if(fastPtr.next == fastPtr) {
return fastPtr;
}
}
//其余情况
while(fastPtr!=null) {
fastPtr = fastPtr.next;
slowPtr = slowPtr.next;
if(fastPtr != null) {
fastPtr = fastPtr.next;
} else {
return null;
}
if(fastPtr == slowPtr) {
System.out.println("ok");
break;
}
}
if(fastPtr == null) {
return null;
}
slowPtr = head;
while(fastPtr != slowPtr) {
fastPtr = fastPtr.next;
slowPtr = slowPtr.next;
}
return fastPtr;
}
}