找带环单向链表的环入口

来源:互联网 发布:域名和空间费用 编辑:程序博客网 时间:2024/06/05 09:15

题目:一个链表中包含环,请找出该链表的环的入口结点。

这是一个在面笔试中问烂了的问题,虽然以前也做过,也知道怎么做,但是总是想推导出具体的数学公式,这样才具有 说服力,今天又重新温习了一下,做了一下数学公式的推导,然后做一下总结;


1、做此类题首先得判断单链表 是否有环,当然这个题目已经告诉我们是有环的链表啦。

判断有环的方法就是用两个快慢指针p1、p2,p2的速度为P1的两倍,两个指针同时从链表的头结点开始出发,当两个结点再一次相遇的时,说明此链表有环。

2、光判断有环还不够,下一步就是要找到环的入口,这一步的推导相对麻烦一些。

且看下图




     从图中可以看出,直线部分的长度为L1,环的长度为L2,入口点到第一次相交点的长度为a。

      因为p2的速度是p1的两倍,所以p2肯定是先到达环里面,当p1和p2再环内相遇的时候,p2走过的距离为L1+n*L2+a; 而p1走过的距离为L1+a;写到这里很多人可能会迷惑,为什么p1所走的距离不是L1+m*L2+a呢(m<n)。是这样的,当两个指针在环内第一次相遇的时候p1在环内走过的距离肯定不会超过环的长度。因为当p1刚刚进入环的时候,如果p1和p2没有相遇,那么p1和p2的最大距离为L2-1,这一点相信大家都能明白,而p2的速度为p1的两倍,所以p1最多走到环的一半的时候p2一定能追上p1。


所以可以列出下面的数学式子



从上面的式子可以看出,L1+a的长度为L2的n倍,也就是说,可以先让一个指针从入口结点先走a步(此时恰好是上面所说的交点位置),然后另一个指针从链表的头结点以相同的速度走,当两个指针再次相遇的时候,相遇结点一定是环的入口结点


java代码实现如下

/* public class ListNode {    int val;    ListNode next = null;    ListNode(int val) {        this.val = val;    }}*/public class Solution {     ListNode EntryNodeOfLoop(ListNode pHead){        if(pHead == null || pHead.next == null)            return null;        ListNode p1 = pHead;        ListNode p2 = pHead;        while(p2 != null && p2.next != null ){            p1 = p1.next;            p2 = p2.next.next;            if(p1 == p2){                p2 = pHead;                while(p1 != p2){                    p1 = p1.next;                    p2 = p2.next;                }                if(p1 == p2)                    return p1;            }        }        return null;    }}



1 0
原创粉丝点击