LeetCode160:相交链表

1、要求

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
在这里插入图片描述
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。

自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0 listA - 第一个链表 listB - 第二个链表
skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数 skipB - 在 listB
中(从头节点开始)跳到交叉节点的节点数 评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB
传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案。

2、示例

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at ‘8’
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为
[5,6,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。 — 请注意相交节点的值不为
1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点)
是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点)
在内存中指向相同的位置。

前置条件,如果在自己的工具中测试时,需要创建ListNode类

public class ListNode {
    public int val;
    public ListNode next;

    public ListNode(int x){
        val=x;
    }
}

3、题目解析

先解析一下题目的意思吧,如果把题目解析明白了,这个题本身并不难,但由于官方解释的有点懵;
这里的相交的意思是值和位置都得相同。所以类似于=== 和 ==的区别:一个要求值和类型都等;一个只要求值相等就行;
下面的是一个大佬发表的评论,我借鉴来了,当时看完就懂了

pA走过的路径为A链+B链
pB走过的路径为B链+A链
pA和pB走过的长度都相同,都是A链和B链的长度之和,相当于将两条链从尾端对齐,如果相交,则会提前在相交点相遇,如果没有相交点,则会在最后相遇。
pA:1->2->3->4->5->6->null->9->5->6->null
pB:9->5->6->null->1->2->3->4->5->6->null

4、解题思路

方法一:HashSet集合

判断两个链表是否相交,可以使用HashSet进行存储判断;
首先遍历链表A,然后将链表A中的结点加入到哈希集合中,然后遍历链表B,对于遍历到的每个节点,判断是否在哈希集合中:

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

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

public class LeetCode160 {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        //创建HashSet集合
        HashSet<ListNode> listNodes = new HashSet<>();
        //如果链表A不为空,则添加到创建的哈希集合中
        while (headA != null){
            listNodes.add(headA);
            headA = headA.next;
        }
        //遍历链表B,对比哈希集合,如果链表B中的值在哈希集合找不到,则返回null
        while (headB != null){
            if (listNodes.contains(headB)){
                return headB;
            }
            headB = headB.next;
        }
        return null;
    }
}

时间复杂度:O(m+n),两个链表各遍历一次
空间复杂度:O(m),需要借用哈希集合存储链表A

方法二:双指针

只有当链表 A 和 B 都不为空时,两个链表才可能相交。
首先判断链表 A 和 B 是否为空,如果其中至少有一个链表为空,则两个链表一定不相交,返回 null。
如果两个两个链表都不为空,在进行以下判断:

  • 如果指针A不为空时,则指向下一个节点;如果指针B不为空时,则指向下一个节点;
  • 如果指针A为null时,则将指针A指向链表B的头节点,然后进行指向B的下一个节点;
  • 如果指针B为null时,则将指针B指向链表A的头节点,然后进行指向A的下一个节点;
  • 直至A和B指针指向同一个节点或者都为空时,返回A和B指向的节点或者返回null
  • 如果能有相交的地方,在相交头一个节点位置,链表A和链表B到达末尾的距离是一样的
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    //双链表
    if (headA == null || headB == null){
        return null;
    }
    ListNode A = headA,B = headB;
    while (A != B){
        A = A == null ? headB : A.next;
        B = B == null ? headA : B.next;
    }
    return B;
}

时间复杂度O(m+n),最差的情况是这样
空间复杂度O(1)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值