刷LeetCode Hot 100刷到第22题“相交链表”的时候,我停了一下。这题在题目列表里长得不起眼,描述也短:给两个单链表的头节点,找出它们相交的起始节点,不相交就返回null。但真把它放在面试场景里,它几乎是一道“照妖镜”——既能看出一个人有没有真正理解链表的基本概念,也能看出算法思维是背套路还是真的推导过。这篇文章就把这道题从题目本意、经典解法、代码细节到面试延伸一次说透,适合正在刷hot 100的求职者,也适合想夯实链表基础、搞懂双指针本质的开发者。
1. 题目本意拆解:相交比的是节点本身,不是节点值
1.1 先看清题目的准确描述
题目给出两个单链表的头节点headA和headB,要求返回两个链表相交的起始节点。如果两个链表没有交点,返回null。题目保证整个链式结构中不存在环。官方示例里有个非常经典的case:
- listA = [4,1,8,4,5]
- listB = [5,0,1,8,4,5]
从值上看,两个链表都出现了“1”和“8”,但相交的起始节点是值为8的那个节点,而不是值为1的那个节点。这是这道题最容易踩的第一个坑:两个链表可能会有值相同的节点,但它们并不是同一个节点。
要理解这一点,得回到链表的结构本身。单链表节点是一个对象,包含val和next两个字段。两个节点“相交”,意味着从某个节点开始,两个链表共享的是同一批节点对象,而不是值恰好相等的一批节点。也就是说,两个链表的尾部是同一个内存地址,从交点开始,next指针指向的都是同一块内存区域。如果用Java或Python写过链表,可以直接说:比较的是对象的引用,不是对象的属性。
1.2 为什么很多人第一反应会错
我在实际面试模拟里见过不少候选人,上来就说“用两个指针分别走,值相等的时候就是交点”。这个思路看起来合理,但漏洞很明显:链表A里有个值为8的节点,链表B里也有个值为8的节点,它们的next可能指向完全不同的后续节点,只是恰好这个位置的数字一样而已。如果把值相等当作相交,返回值就错了。
还有一个常见错误是“把两个链表转成数组/列表,然后找公共后缀”。这个思路方向是对的——它抓住了“相交后完全重合”这个特征,但实现起来需要额外空间,而且在面试中不够优雅。更关键的是,它没有用到链表本身的特性,属于用线性表思维去解链表题,容易被追问到更优解法。
1.3 哈希集合法:最容易想到的正确解法
如果只是想快速做对,哈希集合是最稳的。思路分三步:
- 遍历headA,把每个节点对象(注意是节点引用)存入HashSet。
- 遍历headB,依次检查当前节点是否在集合里。
- 第一个命中的节点就是交点;遍历完都没有命中,返回null。
这个解法能在O(m + n)时间内完成,m和n分别是两个链表的长度,但空间复杂度是O(m)。简单来说,就是用空间换时间。
不过,在Hot 100里做这题,哈希集合只能算及格。因为题目后面还藏着“尽量满足O(1)空间复杂度”这个进
