1.题目描述
2.思路
第一步:判断是否有环
快慢指针(fast 每次走 2 步,slow 走 1 步);
如果 fast == slow,说明有环;
第二步:找环的起始节点
两指针:一个从头走,一个从相遇点走,每次走一步;
相遇点就是入环节点。
补充:
(1)在本题的求解过程中,双指针会产生两次“相遇”。
双指针的第一次相遇:
设两指针 fast,slow 指向链表头部 head 。
令 fast 每轮走 2 步,slow 每轮走 1 步。
(2)双指针第二次相遇:
令 fast 重新指向链表头部节点。此时 f=0,s=nb 。
slow 和 fast 同时每轮向前走 1 步。
当 fast 指针走到 f=a 步时,slow 指针走到 s=a+nb 步。此时两指针重合,并同时指向链表环入口,返回 slow 指向的节点即可。
模拟指针两次相遇的动态图
3.代码实现
class ListNode {
int val;
ListNode next;
public ListNode() {
}
ListNode(int x) {
val = x;
next = null;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public class H142 {
public ListNode detectCycle(ListNode head) {
ListNode slow=head;
ListNode fast=head;//一开始要同起点出发
//1.存在空节点或者一个节点的,返回null
if(head==null||head.next==null)
{
return null;
}
//3.开始执行快2慢1的操作
while(fast!=null&&fast.next!=null)//不能是链表的情况,要同时存在。
{
fast=fast.next.next;
slow=slow.next;
if(fast==slow)//第一次相遇,说明存在环。快慢指针一起从原点出发
{
//第二次相遇,快慢指针每次走一步
fast=head;//第二次相遇快指针从head开始走
while(fast!=slow)//用if和while都可以,说明p1和p2 第二次还没相遇
{
fast=fast.next;
slow=slow.next;
}
return fast;//如果p1=p2,说明此时快慢指针相遇。第二次相遇过程,慢指针叫p2,快指针叫p1
}
}
return null;//说明无环
}
public static void main(String[] args)
{
H142 test = new H142();
// 构建链表:3 -> 2 -> 0 -> -4
ListNode node4 = new ListNode(-4);
ListNode node3 = new ListNode(0, node4);
ListNode node2 = new ListNode(2, node3);
ListNode head = new ListNode(3, node2);
// 构建环:让 -4 指向 2,形成环
node4.next = node2;
ListNode res = test.detectCycle(head);
System.out.print("输出返回链表开始入环的第一个节点的结果;");
if (res != null) {
System.out.print(res.val);
}
else
{
System.out.print("无环");
}
}
}