题目描述

✅ LCR 023. 相交链表

image-20260928235012602

image-20260928235012603

image-20260928235012604

image-20260928235012608

题意分析

给定两条无环单链表,返回它们第一个共享的节点;没有公共节点则返回空。共享指同一个节点对象,两个节点的值相等不能算相交。

单链表每个节点只有一个后继,所以一旦相交,后面的整段都会重合。两条链各自的前缀长度可以不同,目标是找到公共后缀的起点,并保持所有原连接不变。

解法:双指针换链抵消长度差

核心思路

[!blue]

若已知两条链的长度,可以让长链指针先走多出的部分,再同步前进。换链法实现相同的对齐效果,但不必显式计算长度差。

指针 a 从 A 出发,走到空后切换到 B 的头;b 从 B 出发,走到空后切换到 A 的头。设两条独占前缀分别有 x、y 个节点,公共后缀有 z 个节点。

换链后到公共入口之前,a 先经过 A 的 x+z 个节点,再经过 B 的 y 个独占节点;b 则先经过 y+z 个节点,再经过 A 的 x 个独占节点。两边合计都为 x+y+z,且都经历一次“从空切到另一头”的更新,所以会在同一轮到达公共入口。若独占前缀等长,它们在第一次扫描时就已相遇。

换链之前不同长度造成的错位,在每个指针补走另一条链的前缀后被抵消。公共入口之前都是独占节点,无法按引用相等,因此返回的就是第一个公共节点。

不相交时,每个指针最终都走过两条链,在至多 m+n+1 次更新后同时为空。循环条件 a != b 同时覆盖“相交节点相同”和“都为空”两个出口。应等当前指针为空后再换链,保留这个能让无交点情况结束的状态。

解题步骤

  1. 初始化 a = headA、b = headB。
  2. 当两个引用不相等时,分别更新它们。
  3. 当前指针非空就走向后继,为空就切到另一条链的头。
  4. 循环结束返回 a,它是公共入口或空指针。

代码实现

class Solution {
    ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode a = headA;
        ListNode b = headB;

        while (a != b) {
            // 换链抵消长度差;没有交点时两个指针最终同时为空。
            a = a == null ? headB : a.next;
            b = b == null ? headA : b.next;
        }

        return a;
    }
}
func getIntersectionNode(headA, headB *ListNode) *ListNode {
    a, b := headA, headB
    for a != b {
        // 换链抵消长度差;没有交点时两个指针最终同时为空。
        if a != nil {
            a = a.Next
        } else {
            a = headB
        }
        if b != nil {
            b = b.Next
        } else {
            b = headA
        }
    }
    return a
}

复杂度分析

  • 时间复杂度:$O(m+n)$,每个指针至多遍历两条链各一次,并进行一次链头切换。
  • 空间复杂度:$O(1)$,只维护两个指针,原链表结构不变。

关键点总结

[!green]

  • 相交后共享整条后缀,对齐进入后缀的时刻即可找到入口。
  • 各自走完本链再接另一链,自动抵消独占前缀的长度差。
  • 从空节点换链这一步在两侧相同,精确数更新次数时不能忽略。
  • 引用相等既表示找到交点,也能表示不相交时双方都到空。

易错点总结

[!yellow]

  • 比较节点值会把内容相同的不同节点误判为公共节点。
  • 在尾节点直接跳转而不允许经过空状态,会使无交点时失去正常的终止出口。
  • 不应为了拼接遍历路径而修改实际 next,换链只改变局部指针变量。
  • 两个头本来相同时直接返回,任一链为空也能由相同循环自然处理。

相似题目

题目 难度 关联与区别
补充题 119. 链表相交判定(允许有环) 中等 本题两链表无环,切换链头可消除长度差;允许带环后还需区分入环点与同环情形。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/58673739
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!