题目描述
两条链表可能从某个节点起完全重合(是同一批节点),返回第一个公共节点,不相交返回 null。
思路解析
暴力两两比对太慢。关键观察:相交后两条链尾巴一样长。只要把较长的那条先走掉「多出来的长度」,两个指针就站在距离终点相同的位置上,再一起走必然同时到达相交点。
① 各走一遍量出 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)
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。短短四行,无需量长度。
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 → ✅ 走到头要跳到"对方"的头(换错成自己的头就永远错位)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。