在问 · 算法题解

160. 相交链表

简单链表双指针(交换起点)力扣原题 ↗

题目描述

给出两条单链表的头节点 headA 和 headB。两条链表可能从某个节点开始共用后面的全部节点,这个节点就是相交起点。返回相交起点;若两条链表没有公共节点,返回 null。

相交指的是同一个节点对象,而不是节点值相等。整个结构中没有环。函数结束后,两条链表必须保持原来的结构。

评测时会给出 intersectVal(相交起点的值,不相交时为 0)、数组形式的 listA 与 listB,以及 skipA、skipB(分别表示从各自头节点走多少个节点到达相交起点)。系统据此建好链表,只把 headA 和 headB 交给你的函数。返回值正确即判为通过。页面上的输出显示相交起点的值,不相交时显示 null。

示例 1
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:8

解释:A 中前 2 个节点、B 中前 3 个节点之后,两条链表汇合到值为 8 的同一个节点。两边值为 1 的节点是不同的对象,不算相交。

示例 2
输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:2

解释:A 跳过 3 个节点、B 跳过 1 个节点后,汇合到值为 2 的节点。

示例 3
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null

解释:两条链表没有公共节点,返回 null。

数据范围

  • listA 有 m 个节点,listB 有 n 个节点。
  • 1 <= m, n <= 3 * 10^4
  • 1 <= Node.val <= 10^5
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 两条链表不相交时,intersectVal 为 0。
  • 两条链表相交时,intersectVal == listA[skipA] == listB[skipB]。

进阶:能否做到 O(m + n) 时间、只用 O(1) 额外空间?

解题思路:双指针(交换起点)

双指针分别走 A、B;走到末尾后切换到另一条链表。两者总行程都是 len(A)+len(B),会在相交点或 None 汇合。

为什么正确

切换后,两个指针还未走过的路径长度相同,因此相遇位置必然一致。

复杂度分析

时间 O(m+n),空间 O(1)。

易错点

比较节点对象身份而非节点值;不同节点可能有相同值。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def getIntersectionNode(self, headA,headB):
        a,b=headA,headB
        while a is not b:
            a=headB if a is None else a.next
            b=headA if b is None else b.next
        return a

载入编辑器,自己跑一遍 →

其他解法

两种方法时间都是 O(m+n);哈希集合用额外空间换取直观,双指针利用两条路径总长相等做到 O(1) 空间。

解法 2:哈希集合 时间 O(m+n),空间 O(m)

先遍历链表 A,把每个节点的引用放进哈希集合。再遍历链表 B,第一个出现在集合中的节点就是相交起点。B 走完都没有命中,返回空。

思路直接,容易想到。需要 O(m) 额外空间,不满足进阶要求的 O(1) 空间。

class Solution:
    def getIntersectionNode(self, headA, headB):
        seen = set()
        a = headA
        while a:
            seen.add(a)
            a = a.next
        b = headB
        while b:
            if b in seen:
                return b
            b = b.next
        return None

链表 专题的其他题目

查看 链表 全部题目 →