题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
实现
判断是否有环:
- p1,p2同时从头节点出发
- p1每次走一步,p2每次走两步
- 快的追上慢的,有环
环的入口
- 初始化:p1,p2都指向头节点
- 环有n个节点,p1先走n步
- p1,p2再同时走
- 相遇的节点便是入口
/**23 链表中环的入口节点*/
public class C23_list_EntryNodeOfLoop {
static ListNode getMeetNode(ListNode head) {//快慢指针相遇的点
if (head == null) { return null; }
ListNode slow = head.next; //慢指针
if (slow == null) { return null; }
ListNode fast = slow.next; //快指针
while (fast != null && slow != null) {
if (fast == slow) { //相遇的点
return fast;
}
slow = slow.next;
fast = fast.next;
if (fast != null) { fast = fast.next; } //存在环
}
return null;
}
//找到环中任意节点,就可以得出环中节点数目,并找到入口
public static ListNode EntryNodeOfLoop(ListNode head) {
ListNode meetNode = getMeetNode(head);
if (meetNode == null) return null;
//获得环中节点数目
int count = 1;
ListNode node1 = meetNode;
while (node1.next != meetNode) {
node1 = node1.next;
++count;
}
//先移动node1,次数为环中节点的数目
node1 = head;
for (int i = 0; i < count; i++) {
node1 = node1.next;
}
//再移动node1和node2
ListNode node2 = head;
while (node1 != node2) {
node1 = node1.next;
node2 = node2.next;
}
return node1;
}
}
Test
public static void main(String[] args) {
ListNode node1 = new ListNode(1);
ListNode node2 = new ListNode(2);
ListNode node3 = new ListNode(3);
ListNode node4 = new ListNode(4);
ListNode node5 = new ListNode(5);
ListNode node6 = new ListNode(6);
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node3;
System.out.println(EntryNodeOfLoop(node1).val);
}