链表17:链表判环

题目:如何判断一个单链表是否有环?有环的话返回进入环的第一个节点的值,无环的话返回-1。如果链表的长度为N,请做到时间复杂度O(N),额外空间复杂度O(1)。

给定一个单链表的头结点head(注意另一个参数adjust为加密后的数据调整参数,方便数据设置,与本题求解无关),请返回所求值。

详见LB7,只是返回值不同,是返回结点值或者-1。

普通方法,空间复杂度为O(1),使用hash表,将每个遍历的对象放入到hash中,然后逐个向下遍历,每遍历一个去hash表中寻找有无相同的对象;如果有就说明循环,即有环;注意,只要有环,总是能够遍历有相同的对象,环不可能无限大。如果pcur==null那么显然无环。

public class ChkLoop {
     public int chkLoop(ListNode head, int adjust)
    {
        //特殊的输入
        if (head==null) return -1;
        //计算得到环中结点的数目
        int nodesNumberOfLoop=this.NodesNumberOfLoop(head);
        //如果没有环,直接返回null
        if(nodesNumberOfLoop==0) return -1;
        
        //如果有环,并且已知环的结点数目为n,来找环的入口结点
        ListNode p1=head;
        ListNode p2=head;
        //指针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.val;
    }
    
    //先找出链表中环的结点数目
    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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值