题目:
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:
1.如何确定一个链表中包含环:
定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个一次走两步如果走的快的指针追上了走的慢的指针,就说明链表包含环。
如果链表中有环
计算环中节点的个数:
因为在判断链表中是否有环时,当两个指针相遇时,说明有环,而且两个指针相遇的节点肯定在环中,从当前这个节点再进行移动,边移动边计数,当再次回到这个点时,就得到环中节点的个数。
2.如何找到环出口:
先定义两个指针p1,p2,指向链表的头节点。
如果链表中的环有n个结点
先将p1在链表上向前移动n个节点。
然后两个节点相同速度移动,当p1的位置跟p2相等时,说明p1,p2到了入口节点
因为p2到入口节点时,p1已经绕环走了一圈
代码
public static class ListNode{
int m_value;
ListNode m_pNext;
ListNode(int m_value){
this.m_value=m_value;
}
}
//判断是否是环
public static ListNode MeetingNode(ListNode pHead){
if(pHead==null)
return null;
ListNode pSlow=pHead.m_pNext;
if(pSlow==null)
return null;
ListNode pFast=pSlow.m_pNext;
while (pFast != null && pSlow != null){
if(pFast==pSlow)
return pFast;
pSlow=pSlow.m_pNext;
pFast=pFast.m_pNext;
if(pFast!=null){
pFast=pFast.m_pNext;
}
}
return null;
}
//找出环的入口节点
public static ListNode EntryNodeOfLoop(ListNode pHead){
ListNode meetingNode=MeetingNode(pHead);
if(meetingNode==null){
return null;
}
//计算环中节点的数目
int nodesInLoop=1;
ListNode pNode1=meetingNode;
while (pNode1.m_pNext!=meetingNode){
pNode1=pNode1.m_pNext;
++nodesInLoop;
}
//先移动pNode1,次数为环中节点的数目
pNode1=pHead;
ListNode pNode2=pHead;
for(int i=0;i<nodesInLoop;i++){
pNode1= pNode1.m_pNext;
}
//再移动pNode1和pNode2
while (pNode1!=pNode2){
pNode1=pNode1.m_pNext;
pNode2=pNode2.m_pNext;
}
return pNode1;
}
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.m_pNext=node2;
node2.m_pNext=node3;
node3.m_pNext=node4;
node4.m_pNext=node5;
node5.m_pNext=node6;
node6.m_pNext=node3;
ListNode result = EntryNodeOfLoop(node1);
if(result==null){
System.out.println("此链表不是环");
}else {
System.out.println("入口节点是:"+result.m_value);
}
}