剑指offer第二版面试题23:链表中环的入口节点(java)

题目描述:
如果一个链表中包含环,如何找出环的入口节点?

分析:
可以用两个指针来解决这个问题。先定义两个指针P1和P2指向链表的头结点。如果链表中环有n个结点,指针P1在链表上向前移动n步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。
  剩下的问题就是如何得到环中结点的数目。我们可以使用一快一慢的两个指针。如果两个指针相遇,表明链表中存在环。两个指针相遇的结点一定是在环中。可以从这个结点出发,一边继续向前移动一边计数,当再次回到这个结点时就可以得到环中结点数了。

代码如下:

/**
 * 链表中环的入口节点
 * 
 * 思路:
 *      1.判断是否存在环,并找到快慢两个指针相遇的位置
 *      2.根据找到的这个相遇位置,统计环中节点的数目n,先让快指针走n步,然后快慢两个指针一起运动,快慢指针相遇时的节点就是环的入口节点
 */
public class EnterNodeInLink {

    public ListNode getEnterNode(ListNode head){
        //参数校验
        if(head == null){
            return null;
        }

        //如果有环,第一个和第二个指针在环中相遇时的节点
        ListNode meetingNode = meetingNode(head);

        int ringLength = 0;                 //环的长度
        if(meetingNode != null){            //如果存在环,就求出环的长度
            ListNode tempNode = meetingNode;
            meetingNode = meetingNode.next;
            while(meetingNode != tempNode){
                ringLength++;
                meetingNode = meetingNode.next;
            }
            ringLength++;
        }else{                              //如果不存在环,就返回null
            return null;        
        }

        ListNode ahead = head;              //第一个指针
        ListNode behind = head;             //第二个指针

        while(ringLength > 0){
            ahead = ahead.next;             //第一个指针先在链表上向前移动ringLength步
            ringLength--;
        }
        while(ahead != behind){
            ahead = ahead.next;
            behind = behind.next;
        }
        return behind;
    }

    //在链表存在环的情况下,找到一快一慢两个指针相遇的节点
    public ListNode meetingNode(ListNode head){
        //参数校验
        if(head == null){
            return null;
        }
        ListNode behind = head.next;        //后面的指针

        //如果只有一个节点直接返回null
        if(behind == null){
            return null;
        }
        ListNode ahead = behind.next;       //前面的指针

        while(behind != null && ahead != null){
            if(behind == ahead){
                return ahead;
            }
            //behind指针在链表上移动一步
            behind = behind.next;
            //ahead指针在链表上移动两步
            ahead = ahead.next;
            if(ahead != null){
                ahead = ahead.next;
            }
        }
        return null;
    }

    public static void main(String[] args) {
        EnterNodeInLink test = new EnterNodeInLink();

        ListNode head = new ListNode();
        ListNode temp1 = new ListNode();
        ListNode temp2 = new ListNode();
        ListNode temp3 = new ListNode();
        ListNode temp4 = new ListNode();
        ListNode temp5 = new ListNode();

        head.value=1;
        temp1.value=2;
        temp2.value=3;
        temp3.value=4;
        temp4.value=5;
        temp5.value=6;
        head.next=temp1;
        temp1.next=temp2;
        temp2.next=temp3;
        temp3.next=temp4;
        temp4.next=temp5;
        temp5.next=null;

        ListNode resultNode = test.getEnterNode(head);
        if(resultNode != null){
            System.out.println(resultNode.value);
        }else{
            System.out.println("您输入的参数有误!");
        }
    }
}

class ListNode{
    int value;
    ListNode next;
}

猜你喜欢

转载自blog.csdn.net/weixin_37672169/article/details/80167240