1.题目
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
2.思路
step1.首先判断是否存在环:定义两个指针,一个一次走一步,一个一次走两步,快的指针能追上慢的指针则存在环,返回环中相遇的节点 。 要是在到达链表尾部(即plow.next ==null),还没相遇,则不存在环 。
step2:找入口节点:定义两个指针,第一个指针P1走环的长度的步数,第二个指针P2从头开始,两个指针同时开始出发,相遇时的节点即为环入口节点 。(P1先走环的长度,则它之后需要走非环的节点,它走完非环的节点后,第一个就是环的入口节点,即P2,P1相遇时为入口节点)
3.代码实现
public class EntryNodeOfLoop {
class ListNode {
int val;
EntryNodeOfLoop.ListNode next = null;
ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
/**
* 判断链表是否有环,如果存在环返回环中的任一节点
* @param pHead
* @return
*/
public ListNode MeetingNode(ListNode pHead){
if(pHead==null){
return null;
}
ListNode pLow=pHead.next;
if(pLow==null){
return null;
}
ListNode pFast=pLow.next;
while(pLow!=null&&pFast!=null){
if(pFast==pLow){
return pFast;
}
pLow=pLow.next;
pFast=pFast.next;
if(pFast!=null){
pFast=pFast.next;
}
}
return null;
}
/**
* 查找环入口
* @param pHead
* @return
*/
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode meetingNode=MeetingNode(pHead);
ListNode pLow=pHead;
ListNode pFast=pHead;
if(meetingNode==null){
return null;
}
int len=0;
//计算环长度
while(pFast.next!=null&&pFast!=meetingNode){
pFast=pFast.next;
++len;
}
//将pFast指针走环长度
pFast=pHead;
for(int i=1;i<=len;i++){
pFast=pFast.next;
}
while(pLow!=null && pFast!=null){
if(pFast==pLow){
return pLow;
}
pLow=pLow.next;
pFast=pFast.next;
}
return null;
}
@Test
public void test1(){
ListNode listNode6=new ListNode(6);
ListNode listNode5=new ListNode(5,listNode6);
ListNode listNode4=new ListNode(4,listNode5);
ListNode listNode3=new ListNode(3,listNode4);
ListNode listNode2=new ListNode(2,listNode3);
ListNode listNode1=new ListNode(1,listNode2);
listNode6.next=listNode3;
Integer result=EntryNodeOfLoop(listNode1).val;
if(result==3){
System.out.println("测试通过!"+result);
}else{
System.out.println("测试失败!");
}
}
@Test
public void test2(){
ListNode listNode1=new ListNode(1);
ListNode result=EntryNodeOfLoop(listNode1);
if(result==null){
System.out.println("测试通过!"+result);
}else{
System.out.println("测试失败!");
}
}
}