Java算法——11判断两个单链表(无环)是否交叉

题目描述

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

在这里插入图片描述

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

解题思路

  • 方法一:Hash法

如果两个链表相交,那么它们一定会有公共结点,由于结点的地址或引用可以作为结点的唯一标识,因此,通过判断两个链表中的结点是否有相同的地址或引用来判断链表是否相交。

首先遍历链表h1,把遍历到的所有结点的地址存放到HashSet中;接着遍历链表h2,每遍历一个结点,就判断这个结点的地址是否在HashSet中,如果存在,说明两个链表相交并且当前遍历到的结点就是它们的相交点,否则直到链表h2遍历结束,说明两个链表不相交。

算法性能分析

分别遍历两个链表,时间复杂度为O(n1+n2);需要申请额外的存储空间来存储h1中结点的地址,因此空间复杂度为O(n1).

  • 方法二:首尾相接法

将这两个链表首尾相连(如把h1的尾结点链接到h2的头指针),然后检测这个链表是否存在环,如果存在,则两链表相交,而环入口结点即为相交的结点。
在这里插入图片描述

  • 方法三:尾结点法

如果两链表相交,那么从相交点到链表结束都是相同的结点,必然是Y字形。所以,判断两个链表的最后一个结点是不是相同即可。即先遍历一个链表,直到尾部,再遍历另外一个链表,如果也可以走到同样的结尾点,则两链表相交,这时记下两链表的长度n1、n2,在遍历一次,长链表结点先出发前进|n1-n2|步,之后两链表同时前进,每次一步,相遇的第一点即为两个链表相交的第一个点。实现如下:

class LNode {
    /**
     * 数据域
     */
    int data;
    /**
     * 下一个结点的引用
     */
    LNode next;
}
public class Test11 {
    public static LNode isIntersect(LNode head1,LNode head2){
        /**
         * @Author: JavaRecord
         * @Description:判断两个链表是否相交,如果相交则找出交点
         * @Param [head1, head2]
         * @Return linked.list1.LNode
         * @Date 2020/8/23
         * @Time 11:39
         */
        if(head1==null||head1.next==null||head2==null||head2.next==null||head1==head2){
            return null;
        }
        LNode temp1=head1.next;
        LNode temp2=head2.next;
        int n1=0,n2=0;
        //遍历head1,找到尾结点,同时记录head1的长度
        while (temp1.next!=null){
            temp1= temp1.next;
            ++n1;
        }
        //遍历head2,找到尾结点,同时记录head1的长度
        while (temp2.next!=null){
            temp2= temp2.next;
            ++n2;
        }
        //head1和head2有相同的尾结点
        if(temp1==temp2){
            //长链表先走|n1-n2|步
            if(n1>n2){
                while (n1-n2>0){
                    head1=head1.next;
                    --n1;
                }
            }
            if(n1<n2){
                while (n2-n1>0){
                    head2=head2.next;
                    --n2;
                }
            }
            //两个链表同时步进,找出相同的结点
            while (head1!=head2){
                head1=head1.next;
                head2=head2.next;
            }
            return head1;
        }
        //没有相同的尾结点
        else{
            return null;
        }
    }
    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.data = i;
            tmp.next = null;
            cur.next = tmp;
            cur = tmp;
            if (i == 5) {
                p = tmp;
            }
        }
        cur=head2;
        for (; i < 5; i++) {
            tmp = new LNode();
            tmp.data = i;
            tmp.next = null;
            cur.next = tmp;
            cur = tmp;
        }
        //使它们相交于结点5
        cur.next=p;
        LNode interNode=isIntersect(head1,head2);
        if(interNode==null){
            System.out.println("不相交");
        }else{
            System.out.println("交点为:"+interNode.data);
        }
    }
}

程序运行结果:

交点为:5

算法性能分析

时间复杂度O(n1+n2);常数个额外指针,空间复杂度O(1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值