链表中环的入口结点
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
分析
- 第一步:确定一个链表中是否有环
我们可以用两个指针来解决,定义两个指针,同时从链表的头结点触发,一个指针一次走一步,另一个指针一次走两步。如果走的块的指针追上了走的慢的指针,那么链表就包含环。如果走得快的只恨走到链表的末尾都没有追上走的慢的,那么链表就没有环。 - 第二步:如何找到环的入口
还是利用两个指针来解决,先定义两个指针和指向链表的头结点,如果链表中的环有n个节点,那么指针现在链表上向前移动n步,然后两个指针按相同速度向前移动,当第二个指针指向环的节点入口时,第一个指针已经围绕着环走了一圈,又回到入口节点。 - 第三步:如何知道环中节点的数目
在第一步中判断一个链表里是否有环时用到一快一慢两个指针,如果两个指针相遇,那么有环,两个指针相遇的节点一定在环中,那么就可以从这个节点触发,一边继续向前移动一边计数,当再次回到这个节点时就可以得到环中节点的点数。
节点类:
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
实现类:
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next == null) {
return null;
}
ListNode meet = MeetNode(pHead);
if(meet == null ) {
return null;
}
int nodeInLoop = 1;
ListNode pNode = meet, pNode2 = pHead;
while(pNode.next != meet) {
pNode = pNode.next;
++nodeInLoop;
}
pNode = pHead;
for (int i = 0; i < nodeInLoop; i++) {
pNode = pNode.next;
}
while(pNode != pNode2) {
pNode = pNode.next;
pNode2 = pNode2.next;
}
return pNode;
}
public ListNode MeetNode(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 slow;
}
slow = slow.next;
fast = fast.next;
if(fast != null) {
fast = fast.next;
}
}
return null;
}
}