Java数据结构与算法之-----判断两个无环单链表是否交叉

 1  问题

       单链表相交是指两个链表存在完全重合的部分,如:

       

  在上图中,两个链表相交于与节点5,要求判断两个链表是否相交,如果相交,找出相交的节点。

2 问题思路分析

    方法一:HashSet

     由图可知,如果两个链表相交,那么链表肯定有公共的节点。由于节点的地址或者引用可以看做节点的唯一标识,因此,可以通过判断两个链表中共的节点是否有相同的地址或者引用即可。

     1)首先遍历链表1,把遍历到的所有节点的地址存放到hashSet中。

     2)在遍历链表2,每遍历到的一个节点,就判断节点的地址在HashSet中是否存在。如果存在。那么说明两个链表相交,并且当前遍历到的节点就是两个链表的相交点,否则知道链表2遍历结束。说明两个链表不相交。

 

   由于这种方法,分贝要遍历两个链表,因此时间复杂度为O(n1+n2)。n1是链表1的长度,n2是链表2的长度。此外还需要额外的空间来存储链表1的节点地址,因此空间复杂度为O(n1)。

方法二: 首尾相连法

       将两个链表的首尾相连,比如讲链表1的尾结点链接到链表2 的头结点。通过判断链表是否有环,用快慢指针法,两个指针相遇,就有环,有环代表两个链表有交叉。

方法三: 尾结点法

     如果两个链表相交。那么两个链表从相交点到链表结束都是相同的节点,必然是Y型的。因此,只需要判断两个链表的最后一个节点是否相同即可。

   1) 先遍历链表1 ,在遍历链表2, 如果走到同样的结尾,则两个链表相交。记下链表1和链表2 的长度,n1   n2

   2)在遍历一次链表长链表先出发前进|n1-n2|次,之后两个链表同时出发,每遍历一步就是比较一下,第一次出现相同的节点就是两个链表相加的点。

3代码实现:

package linkedlist.Mergelinkedlist;

public class Isintersect {
    public static void main(String[] args) {
        int i=1;
        LNode head1=new LNode();
        head1.next=null;
        LNode head2=new LNode();
        head2.next=null;
        LNode tmp=null;
        LNode cur=head1;
        LNode p=null;
        //构造第一个链表
        for (;i<8;i++){
            tmp=new LNode();
            tmp.date=i;
            tmp.next=null;
            cur.next=tmp;
            cur=tmp;
            if (i==5){
                p=tmp;
            }
        }
        cur=head2;
        //构造第二个链表
        for (i=1;i<5;i++) {
            tmp = new LNode();
            tmp.date = i;
            tmp.next = null;
            cur.next = tmp;
            cur = tmp;
            //使两个链表相交于节点5
            cur.next = p;
        }
        LNode intersectnode= isIntersect(head1, head2);
        if (intersectnode==null){
           System.out.println("不相交");
       }else {
            System.out.println("相交于节点"+intersectnode.date);
    }
}

    /**
     * 判断两个链表是否相交
     * @param head1   链表1的头结点
     * @param head2   链表2的头结点
     * @return   如果不想交返回null  相交返回相交点
     */
    public static LNode isIntersect(LNode head1,LNode head2){
        if (head1==null||head1.next==null||head2==null||head2.next==null||head1==head2){
            return null;
        }
        LNode tmp1=head1.next;
        LNode tmp2=head2.next;
        int n1=0,n2=0;
        //遍历head1,找到尾结点。同时记录head1 的长度
        while (tmp1.next!=null){
            tmp1=tmp1.next;
            ++n1;
        }
        //遍历head2,找到尾结点。同时记录head2 的长度
        while (tmp2.next!=null){
            tmp2=tmp2.next;
            ++n2;
        }
        //head1与head2有相同的尾结点
        if (tmp1==tmp2){
            //长的链表先走|n1-n2|步
            if (n1>n2){
                while (n1-n2>0){
                    head1=head1.next;
                    --n1;
                }
            }
            if (n2>n1){
                while (n2-n1>0){
                    head2=head2.next;
                    --n2;
                }
            }
            //两个链表同时前进,找出相同的节点
            while (head1!=head2){
                head1=head1.next;
                head2=head2.next;
            }
            return head1;
        }else {
            return null;
        }
    }
}

    时间复杂度O(n1+n2)    空间复杂度O(1)   

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值