数据结构与算法分析笔记与总结(java实现)--链表18:有环单链表判断是否相交问题

如何判断两个有环单链表是否相交?相交的话返回第一个相交的节点,不相交的话返回空。如果两个链表长度分别为NM,请做到时间复杂度O(N+M),额外空间复杂度O(1)。给定两个链表的头结点head1head2(注意,另外两个参数adjust0adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

思路:这里已知给定的是两个有环的单链表,要判断这两个有环的单链表是否相交

如何求出环的第一个结点?

方法一:使用剑指offer上面的逻辑:先pslow,pfast遍历得到重合点meetingNode,然后pslow再绕一圈计算出环中的结点数目nodesNumberOfLoop,然后再从头结点开始,p1先走nodesNumberOfLoop步,当p1p2再次重合的位置就是入口结点较为复杂。

方法二:使用视频中的逻辑:先pslowpfast遍历得到重合点meetingNode,然后新的指针p从头结点head开始向下遍历,pslow依然向下遍历,当两者重合时的结点就是入口结点较为方便,不需要计算环内的结点数目,可以用数学方法证明正确性。--之后改用方法2

对于无环链表判断相交较为简单:先求出两个链表的长度length1,length2,diff=length1,length2,长的链表先走diff步,然后一起走逐个结点进行比较。

对于有环单链表判断相交:

①先求出两条链表的入环结点p1,p2

②判断p1与p2是否相同

(1)如果相同,说明两条链表在入环之前已经相交,此时就相当于是对两条从head到入环结点的链表判断相交性。--判断两条无环链表是否相交

(2)如果不相同,说明在入环之前没有相交,则要判断在环中是否相交(理解,如果环中相交,即从某个meetingNode结点相交,那么之后的所有结点都相交,而由于之后的结点都是环,所以如果在环内相交那么这两个环必定完全重合),于是只要从某个入环结点p1开始遍历这个环每个结点都与p2进行比较,如果相等说明相交,如果绕完一圈都不等那么说明不想交。


//已知链表是有环的链表,判断有环链表的第一个交点,有两种情况:入环结点相同;入环结点不相同;返回第一个交点;题目要求是返回boolean值,但是通用的还是返回第一个相交的结点,所以以下代码的核心是public ListNode returnFirstIntersectionNode(ListNodehead1, ListNode head2, int adjust0, int adjust1)方法,只是为了返回boolean而对他进行了一个包装。

publicclass ChkIntersection {

    public booleanchkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {

       ListNodefirstIntersectionNode=this.returnFirstIntersectionNode(head1,head2,adjust0,adjust1);

       return firstIntersectionNode==null ?false:true;

}

//判断两个有环链表是否相交,如果相交返回第一个相交结点,如果不想交返回null

    public ListNodereturnFirstIntersectionNode(ListNode head1, ListNode head2, int adjust0, intadjust1) {

        //先得到两条链表的入环结点

        ListNodeentryNodeOfLoop1=this.entryNodeOfLoop(head1);

        ListNodeentryNodeOfLoop2=this.entryNodeOfLoop(head2);

        //比较两个入环结点是否相同

        if(entryNodeOfLoop1==entryNodeOfLoop2){

            //入环结点相同,则在该结点之前的无环链表上面判断有无相同结点

            //先求出链表从head到入环结点的长度

            intlength1=this.listLength(head1,entryNodeOfLoop1);

            intlength2=this.listLength(head1,entryNodeOfLoop2);

            ListNode longNode=null;

            ListNode shortNode=null;

            int diff=0;

            if(length1<length2){

                longNode=head2;

                shortNode=head1;

                diff=length2-length1;

            }else{

                longNode=head1;

                shortNode=head2;

                diff=length1-length2;

            }

            //长链表先走diff

            for(int i=0;i<diff;i++){

                longNode=longNode.next;

            }

            //一起移动遍历比较

            while(longNode!=entryNodeOfLoop1){

                if(longNode==shortNode) returnlongNode;

                longNode=longNode.next;

                shortNode=shortNode.next;

            }

            return entryNodeOfLoop1;

        }else{

            //入环结点不同,要判断在环中是否相交,即两个链的环是否完全重合

            //先将链表1的入环结点记住

            ListNode p=entryNodeOfLoop1;

            p=p.next;

            while(p!=entryNodeOfLoop1){

                if(p==entryNodeOfLoop2) returnp;

                p=p.next;

            }

            return null;

        }

    }

    //已知一个链表是有环链表,得到这个链表环的入环结点

    public ListNode entryNodeOfLoop(ListNodehead){

        //定义两个指针

        ListNode pfast=head;

        ListNode pslow=head;

        //初始时pfastpslow重合,先走一步再判断

        pslow=pslow.next;

        pfast=pfast.next.next;

        while(pfast!=pslow){

            pslow=pslow.next;

            pfast=pfast.next.next;

        }

        //pslow,pfast必然会重合

        ListNode meetingNode=pslow;

        //根据数学规律得到入环结点

        ListNode p=head;

        while(p!=pslow){

            p=p.next;

            pslow=pslow.next;

        }

        return p;

    }

    //求出链表从headtail的长度

    public int listLength(ListNodehead,ListNode tail){

        int length=1;

        while(head!=tail){

            head=head.next;

            length++;

        }

        return length;

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值