题目:如果一个链表中包含环,如何找出环的入口节点?例如,在如图3.8所示的链表中,环的入口节点3.

解题思路:
一 . 解决这个问题的第一步是如何确定一个链表中包含环。
定义一快和一慢两个指针,开始时慢指针指向第一个节点,快指针指向第二个节点;然后慢指针一次走一步,快指针一次走两步。如果走的快的指针追上了走的慢的指针,那么链表就包含环。如果走的快的指针走到了链表的末尾都没有追上第一个指针,那么链表就不包含环。
二 . 第二步是判断环中有几个节点。
两个指针相遇的节点肯定是在环中。可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,就可以得到环中节点数了。
三 . 第三步就是如何找到环的入口。(本题环中有四个节点)
我们还是用两个指针来解决这个问题。先定义两个指针P1(快指针)和P2(慢指针)指向链表的头节点。如果链表中的环有n个节点,则指针P1先在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第一个指针指向环的入口节点时,第一个指针已经围绕着环走了一圈,又回到了入口节点。

package leetcode;
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class Class_EntryNodeOfLoop {
public static ListNode createList() {
ListNode[] list = new ListNode[5];
for (int i = 0; i < 5; i++) {
list[i] = new ListNode(i + 1);
}
for (int i = 0; i < 4; i++) {
list[i].next = list[i + 1];
}
list[4].next = list[2];
return list[0];
}
public static ListNode isCycle(ListNode pHead) {
if (pHead == null) {
return null;
}
ListNode pSlow = pHead;
ListNode pFast = pHead.next;
while (pSlow != null && pFast != null) {
if (pSlow == pFast) {
return pSlow;
}
pSlow = pSlow.next;
pFast = pFast.next;
if (pFast != null) {
pFast = pFast.next;
}
}
return null;
}
public static ListNode detectCycle(ListNode pHead) {
ListNode meetListNode = isCycle(pHead);
if (meetListNode == null) {
return null;
}
// 确定环中有几个节点
int num = 1;
ListNode p = meetListNode;
while (p.next != meetListNode) {
p = p.next;
num++;
}
/*
* 用一快一慢两个指针 找到环的入口节点 快指针先走num步,之后快慢指针每次都走一步,快慢指针相遇时 即为入口节点
*/
ListNode pSlow = pHead;
ListNode pFast = pHead;
while (num > 0) {
pFast = pFast.next;
num--;
}
while (pSlow != pFast) {
pSlow = pSlow.next;
pFast = pFast.next;
}
return pSlow;
}
public static void main(String[] args) {
ListNode pHead = createList();
ListNode res = detectCycle(pHead);
System.out.println(res.val);
}
}