题目描述:
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 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
解释:链表中没有环。
分析:
首先如果证明链表中有环可以定义两个指针,一个指针slow一次走一步,另一个指针fast一次走两步。如果走的快的指针追上了走的慢的指针,则证明链表中有环。
如何找到环的入口节点呢?
定义两个指针p1和p2,如果链表中的环有n个节点,则指针p1先在链表上移动n步,然后两个指针以相同的速度向前移动,直到他们相遇,他们相遇的节点正好是环的入口节点。
如何得到环中的节点数目呢?
在证明链表中是否存在环时用到了两个指针,(一个快指针,一个慢指针),当两个指针相遇时,则表明链表中存在环。两个指针相遇的节点一定是在环中。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,即可得到环中节点的个数。
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null)
return null;
ListNode fast=head.next.next,slow=head.next;
while(fast!=slow) {
if(fast!=null&&fast.next!=null)
fast=fast.next.next;
else
return null;
slow=slow.next;
}
ListNode comm=slow;
int count=1;slow=slow.next;
while(slow!=comm) {
slow=slow.next;
count++;
}
//System.out.println(count);
slow=head;fast=head;
while(count!=0) {
fast=fast.next;
count--;
}
//System.out.println(count);
while(fast!=slow) {
slow=slow.next;
fast=fast.next;
}
return slow;
}
如何找到第一个入环节点?
- 令慢指针指向head.next 快指针执行head.next.next
- 当二者相遇时,重置fast=head,每次向前移动一步
- 再次相遇即为环的入口节点
public ListNode detectCycle(ListNode head) {
if(head==null||head.next==null||head.next.next==null)
return null;
ListNode slow=head.next,fast=head.next.next;
while(fast!=slow) {
if(fast.next==null||fast.next.next==null)
return null;
fast=fast.next.next;
slow=slow.next;
}
fast=head;
while(fast!=slow) {
fast=fast.next;
slow=slow.next;
}
return fast;
}