题目描述
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
思考一(遍历+哈希表)
先遍历一遍任意一个链表,把每个节点存到哈希表中。再遍历另一个链表的每个节点,判断节点是否在哈希表中存在,如果存在就返回这个节点,这个节点必然是第一个交点。
代码
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
const set = new Set();
let node = headA;
while (node) {
set.add(node);
node = node.next;
}
node = headB;
while (node) {
if (set.has(node)) {
return node;
}
node = node.next;
}
};
思考二(双指针法)
双指针法的核心思路是消除两个链表的长度差异,使它们能够同步到达相交点(如果存在):
- 长度差异是关键障碍:两个链表若相交,从相交点到尾端的部分是共用的,差异只存在于相交点之前的部分。
- 先计算长度差:分别遍历两个链表得到长度 lenA 和 lenB,求出差值 count。
- 让长链表先行:让指向长链表的指针先移动 count 步,此时两个指针到各自链表尾端的距离相等。
- 同步遍历找交点:两个指针同时向后移动,若相遇则该节点为相交起点;若遍历结束仍未相遇,则无交点。
这种方法只需两次完整遍历(计算长度)加一次同步遍历,时间复杂度为 O(m+n),空间复杂度为 O(1),是高效且节省空间的解决方案。
代码
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
let nodeA = headA;
let nodeB = headB;
let lenA = 0, lenB = 0;
while (nodeA) {
lenA++;
nodeA = nodeA.next;
}
while (nodeB) {
lenB++;
nodeB = nodeB.next;
}
let count = Math.abs(lenA - lenB);
if (lenA > lenB) {
nodeA = headA;
nodeB = headB;
} else {
nodeA = headB;
nodeB = headA;
}
while (nodeA && count > 0) {
count--;
nodeA = nodeA.next;
}
while (nodeA && nodeB) {
if (nodeA === nodeB) return nodeA;
nodeA = nodeA.next;
nodeB = nodeB.next;
}
return null;
};
思考三(更简洁的双指针法)
该双指针解法是对“消除长度差”思路的极致简化,核心在于让两个指针“自动抵消”链表长度差异,无需单独计算长度,逻辑更精妙:
- 打破“固定遍历顺序”:不预先计算链表长度,而是让指针 pA 从 headA 出发、pB 从 headB 出发,同步向后遍历。
- “跨界”遍历补全长度差:当某一指针遍历完自身链表(指向 null)时,立即转向另一链表的头部继续遍历。例如:
- 若 lenA < lenB,pA 会先走完 headA,转而遍历 headB;此时 pB 仍在 headB 上,直到 pB 也走完 headB 并转向 headA。
- 最终,两个指针会“自动对齐”到距离各自链表尾端相等的位置(相当于抵消了长度差)。
- 相遇即交点,遍历完即无交点:
- 若两链表相交,pA 和 pB 会在遍历过程中相遇,此时相遇节点就是相交起始节点(因后续路径完全共用)。
- 若两链表无交点,两个指针最终都会遍历完 headA + headB 的所有节点,同时指向 null,循环终止并返回 null。
该方法仅需一次遍历(实际是两指针各遍历“自身链表+另一链表”的部分节点),时间复杂度仍为 O(m+n),但代码更简洁;空间复杂度保持 O(1),且避免了单独计算长度的步骤,执行效率更优。
代码
var getIntersectionNode = function(headA, headB) {
if (headA === null || headB === null) {
return null;
}
let pA = headA, pB = headB;
while (pA !== pB) {
pA = pA === null ? headB : pA.next;
pB = pB === null ? headA : pB.next;
}
return pA;
};
849

被折叠的 条评论
为什么被折叠?



