题目

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

代码

  • 该题目和第12题“链表中倒数第k个节点”方法类似

  • 需要使用快慢两个指针,然后根据指针的移动找到环的入口节点

  • 本题目需要解决三个问题

    • 1、怎么判断链表是否有环?
    • 2、判断有环后,怎么知道环的入口几点在哪?
    • 3、环的节点数目是多少?
  • 答:

    • 问题1、使用两个快慢的指针,分别为p1和p2,然后块指针每次移动两个节点,慢指针移动一个节点。如果块指针追上慢指针,那么就判断链表中有环,但是找到的节点并不一定是环的入口节点,否则没有环。MeetingNode函数就是解决这个问题的

    • 问题2、如何判断环的节点数目?首先根据问题1,记录链表中判断出来的一个节点,我们可以从这个节点出发,重新的走一遍这个环,同时记录出现的节点个数,回到起点节点时,那么次数就是环中节点的个数sum

    • 问题3、根据环中节点的个数,然后将快指针首先移动sum下,慢指针从头链表开始,每次快慢指针都走一个节点,如果出现快慢节点的重合,那么记录下重合的节点,这个节点就是链表中环的入口节点。

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead){
        ListNode meetingNode = MeetingNode(pHead);
        if(meetingNode==null)
            return null;
        int sumLoopNode = 1;
        ListNode loopNode = meetingNode;
        while(loopNode.next!=meetingNode){
            loopNode = loopNode.next;
            sumLoopNode++;
        }
        ListNode pHead1 = pHead;
        for(int i=0;i<sumLoopNode;i++){
            pHead1 = pHead1.next;
        }
        ListNode pHead2 =pHead;
        while(pHead1!=pHead2){
            pHead1 = pHead1.next;
            pHead2 = pHead2.next;
        }
        return pHead1;
    }
    
    public ListNode MeetingNode(ListNode pHead){
        if(pHead==null)
            return null;
        ListNode slowNode = pHead.next;
        if(slowNode==null)
            return null;
        ListNode fastNode = slowNode.next;
        while(slowNode!=null && fastNode!=null){
            if(slowNode==fastNode)
                return slowNode;
            slowNode=slowNode.next;
            for(int i=0;i<2;i++)
                fastNode = fastNode.next;
        }
        return null;
    }
}