图解题库 / 链表 · 双指针

160. 相交链表

简单 含交互动画

学完这道你应该能: 说清它为什么用「双指针」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

题目描述

两条链表可能从某个节点起完全重合(是同一批节点),返回第一个公共节点,不相交返回 null。

链表 A = 1 → 9 → [8 → 4]
链表 B = 3 → [8 → 4]
输出 = 节点 8 (A、B 共用的 8→4)

思路解析

暴力两两比对太慢。关键观察:相交后两条链尾巴一样长。只要把较长的那条先走掉「多出来的长度」,两个指针就站在距离终点相同的位置上,再一起走必然同时到达相交点。

① 各走一遍量出 lenA、lenB;② 让长的那条指针先走 |lenA−lenB| 步;③ 两指针同速前进,第一个相同的节点就是相交点(没有则同时到 null)。

观察 · 尾部 [8,4] 是共用的:绿色的 [8, 4] 在 A、B 里是同一批节点(只是画了两次)。A 长 4、B 长 3,相差 1。

① A 较长 · 先走 1 步:A 比 B 长 1,让 pA 先走 1 步到 9。现在 pA、pB 离各自终点的距离一样了(都还剩 3 个节点)。

② 一起走 · 9≠3,未相遇:现在两个一起走。先看当前:pA 在 9、pB 在 3,不是同一个节点,继续走。

② 走到 8 · 同一个节点 → 相交点!:pA 走到 A 的 8、pB 走到 B 的 8——而这两个 8 是同一个节点(绿色共用段的头)!这就是相交点,返回它。

处理「两条不等长、要对齐尾部」的通用思路:先消掉长度差。还有个更妙的等价写法——pA 走完 A 接着走 B、pB 走完 B 接着走 A,走的总长都是 m+n,自然在相交点相遇。

参考代码(Python)

Python
1def getLen(h):                        # 量长度
2    n = 0
3    while h: n += 1; h = h.next
4    return n
5la, lb = getLen(headA), getLen(headB)
6pa, pb = headA, headB
7for _ in range(abs(la - lb)):         # 长的先走差值
8    if la > lb: pa = pa.next
9    else: pb = pb.next
10while pa is not pb:                   # 一起走到相同节点
11    pa, pb = pa.next, pb.next
12return pa                             # 相交点(或同时为 None)

复杂度分析

  • 时间复杂度:O(m+n) —— 量长度 + 走一遍
  • 空间复杂度:O(1) —— 几个指针

套路模板

记住这个最简写法:谁走到头就换到对方链头继续。两个指针各走 m+n 步,要么在相交点相遇、要么同时为 None。短短四行,无需量长度。

Python
1# 经典等价写法: 各走 m+n, 必在相交点(或null)相遇
2pa, pb = headA, headB
3while pa is not pb:
4    pa = pa.next if pa else headB     # A走完转去B
5    pb = pb.next if pb else headA     # B走完转去A
6return pa

易错点

  • 比较节点的 val → ✅ 比较节点身份 pa is pb(相交是"同一个节点",不同节点可能值相同)
  • 换链时用 pa.next 而非 headB → ✅ 走到头要跳到"对方"的头(换错成自己的头就永远错位)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →94. 二叉树的中序遍历 ← 返回题库