判断两个单链表的相交问题

判断两个单链表相交之前,我们应先判断单链表是否有环,然后就分成了有环链表的相交和无环链表的相交。

第一步:判断单链表是否有环,有就返回第一个入环节点。我们首先要有个清晰的认知就是,如果一个单链表有环,那么遍历链表就永远在环里转下去。对此我们有两种方法判断

第一种:利用hashset的特性,hashset的查询时间复杂度为O(1)。

public Node isHuan(Node head){//判断是否有环,若有环返回入环点(hashSet)
        Node fistLoop=null;
        HashSet<Node> set=new HashSet<>();
        Node cur=head;
        while (cur!=null){
            if(!set.contains(cur)){//判断set中是否已经存储此节点,没有就存入,有就返回第一个入环节点
                set.add(cur);
            }else {
                fistLoop=cur;
                break;
            }
            cur=cur.next;
        }
        return fistLoop;
    }
   

第二种:利用快慢指针

 public Node isHuan1(Node head){//判断是否有环,若有环返回入环点(快慢指针)
        if(head.next==null){
            return head;
        }
        Node first=head.next.next;
        Node slow=head.next;
        while (first!=null &&first!=slow){
            first=first.next.next;
            slow=slow.next;
        }
        //当相等时,first指针指向头指针,并一步步前进,当快慢指针再次相等时,就是第一个入环节点,这个结论可由
        //归纳法证明得知
        if(first==slow){
            first=head;
            while (first!=slow){
                first=first.next;
                slow=slow.next;
                if(first==slow){
                    break;
                }
            }
        }
        return first;
    }

第二步,判断链表是否相交,注意链表相交会有相同的终点,单链表的一个节点指向必然是一个唯一的节点,所以两个链表交叉相交是不可能的

public Boolean intersect(Node head,Node head1){
        Node first=isHuan1(head);
        Node first1=isHuan(head1);
        Boolean flag=false;
        if(first==null && first1==null){//两个无环链表相交
            if(Nointersect(head,head1)!=null){
                flag=true;
            }else {
                flag=false;
            }
        }else if(first!=null && first1!=null){//两个有环链表相交
            if(Loopintersect(head,head1,first,first1)!=null){
                flag=true;
            }else {
                flag=false;
            }
        }else {//不可能相交,相交的单链表必有共同的终点
            return flag;
        }

        return flag;
    }
    public Node Loopintersect(Node head,Node head1,Node first,Node first1){//两个有环链表相交
        Node cur=head;
        Node cur1=head1;
        if(first==first1){
            int n=0;
            while (cur!=first){
                n++;
                cur=cur.next;
            }
            while (cur1!=first1){
                n--;
                cur1=cur1.next;
            }
            cur=n>0?head:head1;//较长的链表
            cur1=n>0?head1:head;//较短的链表
            int len=Math.abs(n);//两个链表的长度差值
            while (len>0){
                cur=cur.next;
                len--;
            }
            while (cur!=cur1 &&cur!=first){
                cur=cur.next;
                cur1=cur1.next;
            }
            return cur;
        }else{
            cur=first.next;
            while (cur!=first){
                if(cur==first1){
                    return first;
                }
                cur=cur.next;
            }
        }
        return null;
    }

    public Node Nointersect(Node head,Node head1){//两个无环链表相交
        Node cur=head;
        Node cur1=head1;
        int n=0;
        while (cur!=null){
            n++;
            cur=cur.next;
        }
        while (cur1!=null){
            n--;
            cur1=cur1.next;
        }
        cur=n>0?head:head1;//较长的链表
        cur1=n>0?head1:head;//较短的链表
        int len=Math.abs(n);//两个链表的长度差值
        while (len>0){
            cur=cur.next;
            len--;
        }
        while (cur!=cur1 &&cur!=null){
             cur=cur.next;
             cur1=cur1.next;
        }
        return cur;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值