链表20:单链表相交判断

题目:给定两个单链表的头节点head1和head2,如何判断两个链表是否相交?相交的话返回true,不想交的话返回false。给定两个链表的头结点head1和head2(注意,另外两个参数adjust0和adjust1用于调整数据,与本题求解无关)。请返回一个bool值代表它们是否相交。

思路:题目要求就是简单的判断是否相交,更加通用的情况是判断有没有相交,如果相交返回第一个相交结点,如果不相交返回null。这道题目是前面两道题目的综合,由于不明确链表里面是否有环,而有环和没环情况下找出第一个相交结点是不同的,因此要分情况来考虑

①特殊输入,head1、head2有一个为null,不相交,交点为null;

②判断head1,head2是否有环—LB9,将这个处理过程提取为一个单独的函数

(1)设置两个指针pfast,pslow进行遍历,如果有环,记录返回入环的第一个结点(即如果pfast.next==null时返回无环,否则求得交点meetingNode,再返回入环结点);

③根据有没有环分别处理

(1)如果链表1,链表2都没环,就是比较两个无环单链表是否相交并返回第一个交点的问题;LB10

(2)如果一个链表有环而另一个链表无环说明必定没有交点;

(3)如果链表1,链表2都有环,就是判断两个有环链表是否相交,如果相交返回第一个交点,如果不相交返回null;LB11

import java.util.*;
public class ChkIntersection {
        //为了代码复用,设置一个标志位,用于表示当参数为null时的情形
    //ListNode mark=new new ListNode(0);
    public boolean chkInter(ListNode head1, ListNode head2, int adjust0, int adjust1) {
        //由于题目仅仅要求判断是否相交,但是采用更加通用的方法返回第一个相交的结点
        ListNode returnFirstIntersectionNode=this.returnFirstIntersectionNode(head1,head2,adjust0,adjust1);
        return returnFirstIntersectionNode==null ? false:true; 
    }
    
    //给定两个链表head1,head2,如果相交,返回相交的第一个结点,否则返回null
    public ListNode returnFirstIntersectionNode(ListNode head1, ListNode head2, int adjust0, int adjust1){
        //特殊输入判断
        if(head1==null||head2==null) return null;
        
        //判断链表是否有环,如果有环返回第一个入环结点
        ListNode entryNodeOfLoop1=this.entryNodeOfLoop(head1);
        ListNode entryNodeOfLoop2=this.entryNodeOfLoop(head2);
        
        //一个链表有环,一个没有环则必定不会相交
        if(entryNodeOfLoop1==null&&entryNodeOfLoop2!=null) return null;
        if(entryNodeOfLoop1!=null&&entryNodeOfLoop2==null) return null;
        
        ListNode intersectionNode=null;
        
        if(entryNodeOfLoop1!=null&&entryNodeOfLoop2!=null){
        //此时,即两个链表都有环,且已经得到入环结点,即寻找两个有环链表的相交结点,调用方法intersectionNodeWithLoop()
            intersectionNode=this.intersectionNodeWithLoop(head1,entryNodeOfLoop1,head2,entryNodeOfLoop2);
        }else{
            //如果两个链表都没有环就是寻找两个无环链表的相交结点的问题,调用方法intersectionNodeWithoutLoop()
            intersectionNode=this.intersectionNodeWithoutLoop(head1,head2,null);
        }
        return intersectionNode;
    }
    
    //已知head!=null判断输入的链表是否有环,如果有环则返回环的第一个结点
    public ListNode entryNodeOfLoop(ListNode head){
        //如果只有一个结点则无环
        if(head.next==null) return null;
        //定义两个指针
        ListNode pfast=head;
        ListNode pslow=head;
        pslow=pslow.next;
        pfast=pfast.next.next;
        while(pslow!=pfast){
            //如果链表有尽头那么一定无环
            if(pfast==null||pfast.next==null) return null;
            pslow=pslow.next;
            pfast=pfast.next.next;
            }
        //此时说明一定有环,记录pfast和pslow在环中的交点
        ListNode meetingNode=pslow;
        //得到入环结点
        ListNode p=head;
        while(p!=pslow){
            p=p.next;
            pslow=pslow.next;
        }
        return p;
}
//已知两个无环链表head1,head2,判断是否相交,若是返回第一个相交结点,否则返回null,为了代码复用,扩展为在head到tailHead之间找相交结点
    public ListNode intersectionNodeWithoutLoop(ListNode head1,ListNode head2,ListNode tailNode){
        //已知head1,head2不为空,即Y字形结构的比较,先得到链表的长度,为了代码复用,此时是求从head到tailHead结点的长度
        int length1=listLength(head1,tailNode);
        int length2=listLength(head2,tailNode);
        ListNode longList=null;
        ListNode shortList=null;
        int diff=0;
        if(length1<length2){
            longList=head2;
            shortList=head1;
            diff=length2-length1;
        }else{
            longList=head1;
            shortList=head2;
            diff=length1-length2;
        }
        //长链表先走diff
        for(int i=0;i<diff;i++){
            longList=longList.next;
        }
        //开始一起向下移动并逐一进行不比较
        while(longList!=tailNode&&shortList!=tailNode){
            if(longList==shortList) return longList;
            longList=longList.next;
            shortList=shortList.next;
        }
        //如果直到末尾还是不同说明链表没有相交
        return null;
    }
    //给定一个无环链表head,求出链表的长度,扩展为求出链表从head到指定结点tailNode的长度
    public int listLength(ListNode head,ListNode tailNode){
        //已知链表不为null
        int count=0;
        while(head!=tailNode){
            head=head.next;
            count++;
        }
        return tailNode==null?count:count++;
    }
//已知两个有环的链表head1,head2,已经得到了有环链表的入环结点,判断是否相交,找出其第一个交点
    public ListNode intersectionNodeWithLoop(ListNode head1,ListNode entryNodeOfLoop1,ListNode head2,ListNode entryNodeOfLoop2){
//已知入环结点entryNodeOfLoop1,entryNodeOfLoop2
//先判断入环结点是否相同
        if(entryNodeOfLoop1==entryNodeOfLoop2){
//在入环结点之前部分的直线链表上面找相交点,即在head到entryNodeOfLoop1结点之间找相交结点
            return this.intersectionNodeWithoutLoop(head1,head2,entryNodeOfLoop1);
        }else{
            //在环里面找相交点
            //记住当前链表2的入环结点
            ListNode p=entryNodeOfLoop2;
            p=p.next;
            while(p!=entryNodeOfLoop2){
                if(p==entryNodeOfLoop1) return p;
                p=p.next;
            }
            return null;
        }
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值