输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
var getIntersectionNode = function (headA, headB) { let A = headA; B = headB; if (A === null || B === null) return null; while (A !== B) { A = A == null ? headB : A.next; B = B == null ? headA : B.next; } return A;};
参考回答
哈希法:
有 A, B 这两条链表, 先遍历其中一个,比如 A 链表,
将 A 中的所有节点存入哈希表。
遍历 B 链表,检查节点是否在哈希表中,
第一个存在的就是相交节点
时间复杂度 O(N), 空间复杂度 O(N)
let data = new Set();while (A !== null) { data.add(A); A = A.next;}while (B !== null) { if (data.has(B)) return B; B = B.next;}return null;
双指针:
使用 a, b 两个指针分别指向 A, B 这两条链表, 两个指针相同的速度向后移动,
当 a 到达链表的尾部时,重定位到链表 B 的头结点
当 b 到达链表的尾部时,重定位到链表 A 的头结点。
a, b 指针相遇的点为相交的起始节点,否则没有相交点
PS: 为什么 a, b 指针相遇的点一定是相交的起始节点? 我们证明一下:
如果我们将两条链表按相交的起始节点继续截断,
A 链表为: a + c,
B 链表为: b + c,
当 a 指针将 A 链表遍历完后,重定位到链表 B 的头结点,然后继续遍历至相交点,
a 指针遍历的距离为 a + c + b,
同理 b 指针遍历的距离为 b + c + a。
时间复杂度 O(N), 空间复杂度 O(1)
let a = headA, b = headBwhile(a != b){a = a ? a.next : nullb = b ? b.next : nullif(a == null && b == null) return nullif(a == null) a = headBif(b == null) b = headA}return a