71.相交链表

一、题目描述

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

图示两个链表在节点 c1 开始相交:
在这里插入图片描述

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、解题思路

解题思路一

官方答案(作参考):判断两个链表是否相交,可以使用哈希集合存储链表节点。

首先遍历链表headA,并将链表headA 中的每个节点加入哈希集合中。然后遍历链表headB,对于遍历到的每个节点,判断该节点是否在哈希集合中:

如果当前节点不在哈希集合中,则继续遍历下一个节点;如果当前节点在哈希集合中,则后面的节点都在哈希集合中,即从当前节点开始的所有节点都在两个链表的相交部分,因此在链表 headB 中遍历到的第一个在哈希集合中的节点就是两个链表相交的节点,返回该节点。

如果链表headB 中的所有节点都不在哈希集合中,则两个链表不相交,返回null。

其实按照这个思路,开始我是有一个不理解的部分的,就是如果按照官方大大的想法,那么对于示例一,headB中第一个出现在集合中的节点应该是1才对,最后我理解了是因为在测试用例中,指明了每个链表在公共节点之前是有几个不公共的节点。

在这里插入图片描述

我根据链表改了一下公共节点为1,和到达公共节点前各链表不公共的节点,测试用例也是通过的:

在这里插入图片描述

代码演示一

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //存放链表A的所有节点
        HashSet<ListNode> visited = new HashSet<ListNode>();
        
        ListNode temp = headA;
        //遍历链表A,将所有节点放到集合中
        while(temp != null){
            visited.add(temp);
            temp = temp.next;
        }

        temp = headB;
        while(temp != null){
            if(visited.contains(temp)){
                return temp;
            }
            temp = temp.next;
        }
        return null;
    }
}

时间复杂度:O(m+n)

空间复杂度:O(m)

解题思路二

这是参考大佬的一个很巧妙的方法,

设「第一个公共节点」为 node ,「链表 headA」的节点数量为 a,「链表 headB」的节点数量为 b ,「两链表的公共尾部」的节点数量为 cc ,则有:

头节点 headA 到 node 前,共有 a−c 个节点;
头节点 headB 到 node 前,共有 b−c 个节点;

在这里插入图片描述

考虑构建两个节点指针 A , B 分别指向两链表头节点 headA , headB ,做如下操作:

指针 A 先遍历完链表 headA ,再开始遍历链表 headB ,当走到 node 时,共走步数为:a + (b - c)
指针 B 先遍历完链表 headB ,再开始遍历链表 headA ,当走到 node 时,共走步数为:b + (a - c)

如下式所示,此时指针 A , B 重合,并有两种情况:a+(b−c)=b+(a−c)

若两链表 有 公共尾部 (即 c > 0) :指针 A , B 同时指向「第一个公共节点」node 。
若两链表 无 公共尾部 (即 c = 0 ) :指针 A , B 同时指向 null。
因此返回 A 即可。

下面以a=5 , b=3 ,c=2 示例的算法执行过程。

在这里插入图片描述
第一步:A一步步向null遍历,B也一步步向null遍历,当B走完时,A还没走完:

在这里插入图片描述

此时,让B走A走过的路,A继续向前走:

在这里插入图片描述

A走到空是,它再去走B走过的路:

在这里插入图片描述

在这里插入图片描述

最后,你会发现当A和B走过相同的路时,他们就会有一个交点:

在这里插入图片描述

代码演示二

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode A = headA, B = headB;

        while(A!=B){
            A = A != null ? A.next : headB;
            B = B != null ? B.next : headA;
        }
        return A;

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值