Senior SWE · VO Coding

LinkedIn 两链表首个交点:O(1) 空间双指针与节点身份

两个指针走完各自链表后切换到另一条,长度差自动抵消;澄清共享节点和环的边界。

题目重点:两个指针走完各自链表后切换到另一条,长度差自动抵消;澄清共享节点和环的边界。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练版链表无环,交集按节点对象身份判断,一旦共享某节点,之后尾部全部共享;没有交点返回 None。
  • 不同节点即便 value 相同也不算相交;若允许环,需单独检测环并分类讨论,不把常规双指针直接套用。

解题路线

  1. 指针 p 从 A、q 从 B 出发,每步前进;到 None 时分别切到 B、A 头。两人最多各走长度 len(A)+len(B),若共享尾部就会在首个共享节点同相位相遇。
  2. 设 A 独有 a 个节点、B 独有 b 个、公共尾 c 个;p 总路径 a+c+b,q 为 b+c+a,故切换后同时进入公共段。若不相交,两者最终都到 None。
  3. 比较 `is`/指针地址而非值;额外空间仅两个游标。可用长度对齐法先算两表长度、长表先走差值,仍 O(1) 空间。

手动走一遍

A: 1→2→X→Y,B: 3→X→Y,两指针切换后在同一个 X 节点相遇;若两个不同节点的 value 都是 X,不相交。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

class Node:
    def __init__(self, value, next=None):
        self.value = value
        self.next = next


def first_intersection(a: Node | None, b: Node | None) -> Node | None:
    """Acyclic lists; intersection is node identity, not equal values."""
    p, q = a, b
    while p is not q:
        p = b if p is None else p.next
        q = a if q is None else q.next
    return p

复杂度

时间 O(A+B),额外空间 O(1)。训练代码 15,000 组随机共享/不共享尾链与独立节点集合 oracle 对照。

易错点与追问

容易失分的边界

  • 按节点 value 而非身份判断交点。
  • 无交点时不切换到 None,造成死循环。
  • 忘记一表为空。
  • 将允许环作为默认情况,却未先检测环。
  • 只返回任意相同值,不保证首个共享节点。

继续深挖

  • 有环且环入口不同怎样判断交点?
  • 如何用长度对齐法证明同样正确?
  • 两条链表可被并发修改时算法前提如何变化?
✓已复制微信号!