如何链表中包含环,如何找出环的入口节点? 例如,在如图所示的链表中,环的入口节点是节点 $3$。
 
解决这道题的思路分为两步,第一步是确定该链表有没有环,我们定义两个指针,一个快指针,一个慢指针,快指针一次性走两步,慢指针一次性走一步。如果有环的话,那么快指针和慢指针就会相遇,并且是在环内相遇;如果没有环的话,那么快指针就会到达尾节点,慢指针与快指针不会相遇。
| public static ListNode meetingNode(ListNode root) {if (root == null) {
 return null;
 }
 
 ListNode slow = root.next;
 if (slow == null) {
 return null;
 }
 
 ListNode fast = slow.next;
 while (slow != null && fast != null) {
 if (slow == fast) {
 return fast;
 }
 slow = slow.next;
 fast = fast.next;
 if (fast != null) {
 fast = fast.next;
 }
 }
 return null;
 
 | 
第二步就是确定环的入口节点,首先我们拿到在第一步中快慢指针相遇的节点,让这个节点遍历环以统计环的数目,当这个节点回到原地时即走了一圈。拿到环的数目 $k$ 以后,我们继续定义两个指针,一个指针先走 $k$ 步,然后两个指针继续走,当两个指针相遇时,即是环的入口节点
 
| public static ListNode entryNodeOfLoop(ListNode root) {
 ListNode meetingNode = meetingNode(root);
 if (meetingNode == null) {
 return null;
 }
 
 int count = 1;
 ListNode loopNode = meetingNode;
 while (loopNode.next != meetingNode) {
 count++;
 loopNode = loopNode.next;
 }
 ListNode ahead = root;
 ListNode after = root;
 
 for (int i = 0; i < count; i++) {
 ahead = ahead.next;
 }
 
 while (ahead != after) {
 ahead = ahead.next;
 after = after.next;
 }
 return after;
 }
 
 | 
测试如下
| public static void main(String[] args) {ListNode root = new ListNode(1);
 root.next = new ListNode(2);
 root.next.next = new ListNode(3);
 root.next.next.next = new ListNode(4);
 root.next.next.next.next = new ListNode(5);
 root.next.next.next.next.next = new ListNode(6);
 root.next.next.next.next.next.next = root.next.next;
 ListNode entryNode = entryNodeOfLoop(root);
 System.out.println(entryNode != null ? entryNode.value : "null");
 }
 
 |