思路:
1、判断是否又环,通过设置两个指针,slow和fast,慢指针一次移动一次,快指针每次前进两个。如果两个指针可以相遇则表示有环。
2、判断环中节点的个数。从相遇点出发绕环一圈回到相遇点则是环中节点的个数N。
3、设置两个指针,第一个指针先向前走环长N步,然后第二个指针再出发,当两个指针相遇的时候就是环的入口节点。
public ListNode MeetingNode(ListNode pHead) {
if (pHead == null) {
return null;
}
ListNode slow = pHead.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 ListNode EntryNodeOfLoop(ListNode pHead){
ListNode meetingNode=MeetingNode(pHead);
if(meetingNode==null){
return null;
}
//求环中节点的数量
int nodesInLoop=1;
ListNode P1=meetingNode;
while(P1.next!=meetingNode){
P1=P1.next;
nodesInLoop++;
}
P1=pHead;
for(int i=0;i<nodesInLoop;i++){
P1=P1.next;
}
ListNode P2=pHead;
while(P1!=P2){
P1=P1.next;
P2=P2.next;
}
return P1;
}
思路二:代码更简洁
1、判断是否又环,通过设置两个指针,slow和fast,慢指针一次移动一次,快指针每次前进两个。如果两个指针可以相遇则表示有环。
经过分析可得:指针相遇点到环入口和头结点到环入口距离相等;当两个指针相遇时,将其中一个指针置为头结点,然后两个指针同步移动,当两个指针相遇时,就是环入口节点!
代码:
public static ListNode EntryNodeOfLoop(ListNode pHead){
//边界值判断
if(pHead==null||pHead.next==null){
return null;
}
ListNode p1=pHead.next;
ListNode p2=p1.next;
while(p1!=p2 && p2!=null){
p1=p1.next;
p2=p2.next;
//空指针判断
if(p2!=null){
p2=p2.next;
}
}
if(p1==p2){
p1=pHead;
while(p1!=p2){
p1=p1.next;
p2=p2.next;
}
}
return p2;
}
注意点:功能测试点:
1、链表中包含环;链表中不包含环;链表中只有一个节点;链表中有多个节点
2、特殊值测试:链表为空(即头结点为空)