寻找链表的交叉点的总结(三种方式实现)

本文总结了三种寻找链表第一个公共交叉点的方法:利用HashSet、先走k步以及通过null节点。方式一通过存储链表A的节点,再遍历B查找公共节点;方式二比较链表长度,然后同步移动指针寻找交点;方式三则是巧妙地利用长度差进行两次循环查找。若无交叉点,指针最终会同时指向null。

寻找链表的第一个公共交叉点

由于链表的特殊的结构,如果链表存在交叉点,那么一定是Y类型的;

方式一 hashSet的方式

1.首先将链表A中的所有的节点加入到HashSet中
2.遍历链表B中所有的节点,如果节点在在hashSet中,直接返回节点(这是由链表的性质决定)
如果所有B中的节点都不在于hashSet中,那么返回null;

private ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        HashSet<ListNode> res = new HashSet<>();
        ListNode cur = headA;
        while (cur != null) {
            res.add(cur);
            cur = cur.next;
        }
        cur = headB;
        while (cur != null) {
            if (res.contains(cur)) {
                return cur;
            }
            cur = cur.next;
        }
        return null;
    }

方式二 先走k步的方式

思想:如果两个链表相交,则最后一个结点一定 是共有的,肯定是从某个节点开始相遇,然后一起走到终点;
1.可以分别遍历2个链表,记录其最后一个 结点和链表长度
2.若2个链表最后一个结点相等,则 相交,否则不相交
3.用指针p1指向较长的那个链表,p2指向 较短的那个链表
4.p1先向后移动|L1-L2|步,然后p1 和p2同时向后移动,每移动一步比较p1和p2是否相 等,当二者相等时,其指向的结点即为交点

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) return null;

        int count = 0;
        ListNode curA = headA,curB = headB;
        // 循环之后,curA指向了headA链表的末尾
        while(curA.next != null) {
            count++;
            curA = curA.next;
        }
        // 循环之后curA指向headB链表的末尾
        while(curB.next != null){
            count--;
            curB = curB.next;
        }
        //末尾节点不想等,不可能存在交叉
        if(curA != curB) return null;

        // curA 来记录比较长的链表
        curA = count > 0 ? headA : headB;
        curB = curA == headA ? headB : headA;
        count = Math.abs(count);
        // 较长的链表先走count步
        while(count > 0) {
            count--;
            curA = curA.next;
        }
        // curA和curB同时向前走,直到curA等于curB
        while(curA != curB) {
            curA = curA.next;
            curB = curB.next;
        }
        return curA;
    }

方式三 奇思妙想的方式(null节点公共节点)

1.这个方式是在第二种方式上衍生出来,只是更加巧妙;
原理:
1.首先是较短的指针到达链表的末尾,从而指向较长链表
2.较长链表到达链表末尾的时候,指向较短链表,
3.重点来了,指针在较长链表的走过的节点数刚刚好是两个链表的长度差
总共经历了两轮循环
第一轮让两个到达末尾的节点指向另一个链表的头部, 最后如果相遇则为交点(在第一轮移动中恰好抹除了长度差)
第二轮: 有交点就返回, 无交点就是各走了两条指针的长度

不会陷入到死循环么?
如果不存在交叉,会同时指向null

public ListNode getIntersectionNodeA(ListNode headA, ListNode headB) {
        if(headA == null || headB == null) {
            return null;
        }
        ListNode pA = headA,pB = headB;
        while(pA != pB){
            pA = pA == null ? pB : pA.next;
            pB = pB == null ? pA : pB.next;
        }
        return pA;
    }

欢迎小伙伴评论交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值