#题目:给一个链表,若其中包含环,请找出该链表的环的入口节点,否则,输出null。
思路:解决这个问题的第一步是先确定链表是否有环,有的话,我们计算出链表环的长度,否则直接返回null。在计算出环的长度n后,我们设置两个指针pNode1、pNode2指向链表的头节点,然后让pNode1先走n步后,再让pNode1与pNode2同时移动,相遇点就是链表中环的入口节点了。
为什么这种方法可以得到入口节点?因为链表的总长度=环长度+无环段长度,pNode1一共走了总长度,pNode1走完环长度,pNode2在相遇前走的长度就是无环段长度,所以相遇的地方就是入口节点了。
还有我们要如何求得环的长度呢?把一个节点指向meetingNode进行遍历比较然后再计数就可以了。
有了清晰的思路之后,我们便可以写出以下代码了:
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode meetingNode=MeetingNode(pHead);
if (meetingNode==null)
return null;
int loopSum=1;//由于是判断tmp.next!=meetingNode,所以loopSum应初始化为1
ListNode tmp=meetingNode;
//计算环的长度
while (tmp.next!=meetingNode)
{
tmp=tmp.next;
loopSum++;
}
ListNode pNode1=pHead,pNode2=pHead;
//pNode1先走环的长度步数
while (loopSum>0)
{
pNode1=pNode1.next;
loopSum--;
}
//两个指针一起移动
while (pNode1!=pNode2)
{
pNode1=pNode1.next;
pNode2=pNode2.next;
}
return pNode1;
}
//获取快慢指针在环中相遇的节点
private ListNode MeetingNode(ListNode pHead)
{
ListNode fast=pHead;//快指针
ListNode slow=pHead;//慢指针
while (fast!=null && fast.next!=null)//注意要考虑fast的双重边界条件
{
fast=fast.next.next;
slow=slow.next;
if (slow==fast)
return slow;
}
return null;
}
}