160.相交链表

160. 相交链表

题目

给你两个单链表的头节点 headAheadB,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交:

img

题目数据保证整个链式结构中不存在环。

注意,函数返回结果后,链表必须保持其原始结构

示例 1:

输入: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出: Intersected at '8'
解释: 相交节点的值为 8

示例 2:

输入: intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出: Intersected at '2'

示例 3:

输入: intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出: null
解释: 两个链表不相交。

提示

  • listA 中节点数目为 m
  • listB 中节点数目为 n
  • 1 <= m, n <= 3 * 10^4
  • 1 <= Node.val <= 10^5
  • 0 <= skipA <= m
  • 0 <= skipB <= n
  • 如果 listAlistB 没有交点,intersectVal0
  • 如果 listAlistB 有交点,intersectVal == listA[skipA] == listB[skipB]

进阶

你能否设计一个时间复杂度 $O(m + n)$、仅用 $O(1)$ 内存的解决方案?

解法

解法一:暴力枚举

因为我比较菜,一开始采用了双重循环,遍历两个链表的所有节点组合,判断是否为同一节点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* getIntersectionNode(struct ListNode* headA,
                                     struct ListNode* headB) {
    struct ListNode* listA = headA;
    while (listA != NULL) {
        struct ListNode* listB = headB;
        while (listB != NULL) {
            if (listA == listB) {
                return listA;
            }
            listB = listB->next;
        }
        listA = listA->next;
    }
    return NULL;
}

复杂度分析

  • 时间复杂度:$O(m \times n)$,其中 $m$ 和 $n$ 分别为两个链表的长度。双重循环导致最坏情况下需要遍历所有节点组合,在 LeetCode 上会超时。
  • 空间复杂度:$O(1)$,只使用了常数额外空间。

解法二:双指针(双链表遍历)

这个解法是从网上搜到的,核心思想是使两个指针走过的距离相同

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* getIntersectionNode(struct ListNode* headA,
                                     struct ListNode* headB) {
    if (headA == NULL || headB == NULL) return NULL;
    struct ListNode* listA = headA;
    struct ListNode* listB = headB;

    while (listA != listB) {
        listA = (listA == NULL) ? headB : listA->next;
        listB = (listB == NULL) ? headA : listB->next;
    }

    return listA;
}

原理分析

设链表 A 的长度为 $m$,链表 B 的长度为 $n$,相交部分的长度为 $c$。

  • 指针 listA 遍历完链表 A(共 $m$ 步)后转向 headB,继续走 $n - c$ 步到达交点,总步数为 $m + (n - c)$。
  • 指针 listB 遍历完链表 B(共 $n$ 步)后转向 headA,继续走 $m - c$ 步到达交点,总步数为 $n + (m - c)$。

两者总步数相等(均为 $m + n - c$),因此会在交点相遇。若两个链表不相交($c = 0$),则两个指针最终都会走向 NULL,此时 listA == listB == NULL,循环结束,返回 NULL

复杂度分析

  • 时间复杂度:$O(m + n)$,每个指针最多遍历 $m + n$ 个节点。
  • 空间复杂度:$O(1)$,只使用了常数额外空间。
posted @ 2026-07-15 16:59  Javenwww  阅读(22)  评论(0)    收藏  举报