
📌 题目简述
给定两个单链表的头节点 headA 和 headB,判断它们是否相交。若相交,返回相交节点;否则返回 None。
注意:相交指从某个节点开始,两个链表共享后续所有节点(结构上"Y"型合并)。
来源:LeetCode 160. Intersection of Two Linked Lists(Easy,但后端/系统岗高频)
🔍 核心思路
本题的关键洞察在于 "消除长度差":
- 若两个链表相交,那么从相交点到末尾的路径是完全相同的。
- 问题在于 A、B 链表在相交前的长度可能不同,导致指针无法同步到达交点。
巧妙解法 :
让两个指针 pA 和 pB 分别遍历 A → B 和 B → A。
- 当
pA走完 A 后跳到 B 的头,pB走完 B 后跳到 A 的头, - 此时两者走过的总路程均为
len(A) + len(B),自动对齐了起点。
💡 为什么有效?
假设 A 独有部分长 a,B 独有部分长 b,公共部分长 c。
- pA 路径:a → c → b → c
- **pB 路径:b → c → a →**c
两人会在第(a + b + c)步同时到达交点(或同时为None)。
⚠️ 痛难点分析
- 误区:直接双指针同步走
若不处理长度差,短链表指针会先到末尾,无法对齐交点。 - 边界条件混淆
-
- 两链表不相交时,最终
pA == pB == None,循环自然退出,无需特殊判断。 - 初学者常误加
if pA is None: break,反而破坏逻辑。
- 两链表不相交时,最终
- "is" vs "==" 的陷阱
题目要求返回同一个节点对象 (内存地址相同),必须用is判断身份,而非值相等。
💻 代码实现
python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
if not headA or not headB:
return None
pA, pB = headA, headB
while pA is not pB:
pA = pA.next if pA else headB
pB = pB.next if pB else headA
return pA
✅ 代码极简、一次遍历、无额外空间,且天然处理了"不相交"情形。
📈 复杂度分析
- 时间复杂度 :O(m + n) ------ 每个指针最多走
m + n步(m、n 为两链表长度)。 - 空间复杂度:O(1) ------ 仅使用两个指针。
🛠 技巧与优化
- 无需计算链表长度:避免了两次遍历(先求长度再对齐)的冗余操作。
- 利用 Python 的 is****语义:精准判断节点身份,符合题目要求。
- 优雅处理 None :当
pA为None时,直接跳转到headB,逻辑连贯。
✨ 对比其他方法:
- 方法1(哈希集):O(m) 空间,需存储 A 的所有节点。
- 方法2(双遍历对齐):需先遍历求长度,再移动长链表指针。
→ 本解法在时间和空间上均最优,且代码最简洁。
🔗 同类题型扩展
- LeetCode 142. 环形链表 II
→ 同样用快慢指针+数学推导找环入口,考察指针技巧。 - LeetCode 21. 合并两个有序链表
→ 练习多指针协同操作,强化链表基本功.