跳到主要内容

0160. 相交链表

题目描述

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

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

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

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

示例

示例 1:

相交节点的值为 8

示例 2:

相交节点的值为 2

示例 3:

没有相交节点

解题思路

第一步:理解相交的含义

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

第二步:暴力解法

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

第三步:哈希表解法

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

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

让两个指针 pq 同时分别从 headAheadB 出发,走到末尾后跳到另一条链表的头。

走过的路径:

  • 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,不会死循环。


扩展思考

如果链表有环怎么办?

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

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

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

相关题目

加载评论中...