链表7:链表中环的入口结点

来源:互联网 发布:039什么意思网络用语 编辑:程序博客网 时间:2024/06/01 21:29

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

思路:对于单链表,如果有环,那么环只能在链表的结尾。即总是可以看做在链表的尾结点有一个指向中间某个结点的指针。关键是如何找到这个环的入口,要探索出环入口的特征。

利用一个性质:假设环的结点数目为n,指针从头结点开始p1比p2先走n步,然后一起向下走,当两个指针发生重合时的位置就是环的入口结点。

于是需要先判断链表是否有环,环中结点的数目n,然后就可以找到入口结点。

如何判断链表是否有环?

使用两个指针p1,p2,速度分别为1,2,同时向下移动,当某时刻两个指针相同时说明有环,且这个重合点在环的内部,然后对于速度为1的指针p1记录位置,之后继续向下移动,当在环中绕满一圈时记录的数值就是结点的数目n。

这里需要两个指针,我们知道链表还是一个链表,只是需要有两个指针来进行遍历,因此采取的方式是:

ListNode p1=pHead;

ListNode p2=pHead;

然后分别对p1,p2进行向下移动遍历,返回时还是返回pHead,即链表还是只有一条的。

特殊情况:

当输入结点为null时,返回null;

当输入单结点时返回null;

当链表没有环时—即要求NodesNumberOfLoop方法能判断出没有环的情况

当链表是一个首尾相连的大环时,要求先判断if(p1==p2) break;再移动p1=p1.next;p2=p2.next;因为可能p1通过移动n后直接就在环的入口结点了。

//给定一个链表,如果这个链表有环找出环的入口结点public class Solution {public ListNode EntryNodeOfLoop(ListNode pHead)    {        //特殊的输入        if (pHead==null) return null;        //计算得到环中结点的数目        int nodesNumberOfLoop=this.NodesNumberOfLoop(pHead);        //如果没有环,直接返回null        if(nodesNumberOfLoop==0) return null;                //如果有环,并且已知环的结点数目为n,来找环的入口结点        ListNode p1=pHead;        ListNode p2=pHead;        //指针p1先走n步        for(int i=0;i<nodesNumberOfLoop;i++){            p1=p1.next;        }        //两个指针开始一起走        while(true){            //注意:这里必须先判断p1==p2;如果链表是一个收尾相连的整个环,那么当p1先走n步后其实p1已经又回到了环的入口,这个结点就是入口            if(p1==p2) break;            p1=p1.next;            p2=p2.next;        }        return p1;    }        //先找出链表中环的结点数目    public int NodesNumberOfLoop(ListNode pHead){                ListNode pfast=pHead;        ListNode pslow=pHead;        int nodesNumberOfLoop=0;        ListNode meetingNode=null;                //先找出两个指针的相遇点meetingNode        //只要是环就不会为null,但是现在还没有确定是否有环        while(true){            //如果遍历时发现没有环,则返回环的大小为0,之后再作处理。注意:return回直接结束方法            if(pfast==null||pslow==null) return 0;             //连续用next可能会有空指针异常            if(pfast.next==null) return 0;            pfast=pfast.next.next;            pslow=pslow.next;                        //初始时指针都在头结点,因此pfast==pslow必然满足,因此必须先移动后再比较            if(pfast==pslow){                //当指针相遇,记录为meetingNode,当前pslow所在位置就是相遇点                meetingNode=pslow;                //结束循环                break;            }        }                //已知meetingNode,求出环的大小;pslow还在相遇点,保留meetingNode,对pslow继续进行遍历        //常识:条件语句放在条件块或者循环体中其实是一样的        while(true){            //初始时,pslow==meetingNode必然成立,因此必须先移动再判断            pslow=pslow.next;            nodesNumberOfLoop++;            if(pslow==meetingNode) break;        }        return nodesNumberOfLoop;    }}


0 0
原创粉丝点击