跳到主要内容

0160. 相交链表

题目描述​

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

图示两个链表在节点 c1 开始相交:

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

注意,函数返回结果后,链表必须 保持其原始结构 。

示例​

示例 1:

相交节点的值为 8

示例 2:

相交节点的值为 2

示例 3:

没有相交节点

解题思路​

第一步:理解相交的含义​

两个链表相交,意味着从某个节点开始,它们共用同一个后缀。不是值相等,而是节点引用相同。

第二步:暴力解法​

对于 A 中的每个节点,遍历 B 看是否有相同节点。时间复杂度 O(m * n)。

第三步:哈希表解法​

把 A 的所有节点存入集合,然后遍历 B,第一个在集合中的节点就是交点。时间复杂度 O(m + n),空间复杂度 O(m)。

第四步:最优解法 - 双指针浪漫相遇​

让两个指针 p 和 q 同时分别从 headA 和 headB 出发,走到末尾后跳到另一条链表的头。

走过的路径:

  • p:a + c + b
  • q:b + c + a

其中 a, b 是两条链表的非公共部分长度,c 是公共部分长度。

两人走的总步数相等,必在交点相遇。如果没有交点,会同时到达 None。

时间复杂度:O(m + n),空间复杂度:O(1)。


完整代码实现​

class ListNode:
def __init__(self, x):
self.val = x
self.next = None

class Solution:
"""
160. 相交链表 - 双指针法

核心思想:
两个指针分别遍历两条链表,走到末尾后跳到另一条链表的头。
走过的总路程都是 a + b + c,必在交点相遇。

时间复杂度:O(a + b)
空间复杂度:O(1)
"""

def getIntersectionNode(self, headA: ListNode, headB: ListNode):
p, q = headA, headB
while p is not q:
p = p.next if p else headB
q = q.next if q else headA
return p

示例推演​

设链表 A:4 -> 1 -> 8 -> 4 -> 5(a = 2,c = 3) 设链表 B:5 -> 6 -> 1 -> 8 -> 4 -> 5(b = 3,c = 3)

p 的路径:4 -> 1 -> 8 -> 4 -> 5 -> (None) -> 5 -> 6 -> 1 -> 8 q 的路径:5 -> 6 -> 1 -> 8 -> 4 -> 5 -> (None) -> 4 -> 1 -> 8

两者都在走了 8 步后在节点 8 相遇。

无交点时: p 走 a + b 步后变为 None q 走 b + a 步后也变为 None 同时到达 None,返回 None


复杂度分析​

解法时间复杂度空间复杂度说明
暴力O(m * n)O(1)双重遍历
哈希表O(m + n)O(m)空间换时间
双指针O(m + n)O(1)最优解

易错点总结​

1. 比较的是节点引用,不是值​

链表相交的定义是节点引用相同,即使两个节点的值一样,如果不是同一个节点也不算相交。

2. 跳到另一条链表头部​

p = p.next if p else headB,不是 headA!这样走的是 a + c + b。

3. 无交点时也正确​

最终会同时变为 None,不会死循环。


扩展思考​

如果链表有环怎么办?​

需要先判断是否有环,以及环的位置,情况会更复杂。

如何只遍历一次就求出交点?​

双指针法本质上已经是单次遍历的最优解法了。

相关题目​

自测​

加载评论中...