算法 | 单链表相交
题目:两个单链表头结点为 headA 和 headB,判断两个单链表是否相交?相交的第一个节点是?不相交,则返回null
🧩 省流总结表(性能优化对比)
| 方法 | 思路 | 时间复杂度 | 空间复杂度 | 是否能找到相交节点 | 性能 | 思路 |
|---|---|---|---|---|---|---|
| 暴力法 | 双重循环 | O(mn) | O(1) | 否 | ❌ 差 | 双重循环遍历所有节点,比较 pA === pB 是否为同一节点引用。 |
| 栈法 | 尾部比较 | O(m+n) | O(m+n) | ✅(最快) | ⚙️ 一般 | 将两个链表节点分别入栈。若栈顶不同,则不相交;若相同则出栈比较,直到遇到不同节点,前一个相同节点即为第一个相交点。 |
| 哈希法 | 哈希存储 | O(m+n) | O(m) | ✅ | ⚙️ 较好 | 遍历链表A,用 Set 存储节点引用;再遍历链表B,若某节点已存在于 Set 中,即为第一个相交节点。 |
| 双指针法 | 指针切换 | O(m+n) | O(1) | ✅ | 🚀 最优 | 指针A/B分别遍历两个链表,走完自己后切换到对方链表头;最终两指针相遇的节点(或null)即为相交点。 |
| 长度差法 | 先走长度差 | O(m+n) | O(1) | ✅ | 🚀 最优 | 先求两个链表长度差d,长链表先走d步;然后同时遍历,首次 pA===pB 即为相交节点。 |
245方法的图解:

分析:若两个单链表相交,则他们从相交的节点开始 会指向同一个内存地址,之后的节点都相同,形成 "Y" 字的形状。

1. 暴力求解
双重 for 循环遍历两个单链表,依次判断两个单链表的节点是否相等,时间复杂度O(m * n),空间复杂度O(1)
function isIntersect(headA, headB) {let pA = headA;while (pA) {let pB = headB;while (pB) {if (pA === pB) return true; // 地址相同pB = pB.next;}pA = pA.next;}return false;
}
2. 栈方法(判断相交 最快)
将两个单链表存到两个栈中,判断栈顶是否相等,若栈顶相等 则表示两单链表相交。依次分别出栈,判断两个节点是否相等,直到不相等的节点,它的前一个相等节点 是第一个相交的节点。时间复杂度O(m + n),空间复杂度O(m + n)
function getIntersectionNodeByStack(headA, headB){const stackA = [], stackB = [];let pA = headA, pB = headB;while(pA){ stackA.push(pA); pA = pA.next; }while(pB){ stackB.push(pB); pB = pB.next; }let lastCommon = null;while(stackA.length && stackB.length){const a = stackA.pop();const b = stackB.pop();if(a === b){lastCommon = a;} else {break;}}return lastCommon;
}
3. 哈希表
使用 Set 哈希表,将一个单链表使用 ES6的 Set 哈希表存储(const set = new set(),set.add(pA) ),循环遍历检查另一个单链表的节点 是否在 set 中(set.has(pB)),若存在 set 中,则 pB 为第一个相交节点。时间复杂度:O(m+n),空间复杂度O(m)
function getIntersectionNodeByHash(headA, headB){const set = new Set();let pA = headA;while(pA){set.add(pA);pA = pA.next;}let pB = headB;while(pB){if(set.has(pB)) return pB; pB = pB.next;}return null;
}
4. 双指针法(推荐最优)
两个指针分别遍历两个单链表,遍历完(到达链表的尾部)后 再遍历另一个单链表的表头。在第二轮遍历中,判断节点是否相等;若相等,则为他们的第一个相交节点(可以是null,表示不相交)。时间复杂度:O(m+n),空间复杂度O(1)
function getIntersectionNode(headA, headB){if(!headA || !headB) return null;let pA = headA, pB = headB;while(pA != pB){pA = pA ? pA.next : headB;pB = pB ? pB.next : headA;}return pA; // 可能是交点,也可能是null
}
5. 长度差法(经典写法)
遍历两个单链表 获取其长度。长的链表 先遍历 差值的部分(多出来的那部分长度),遍历到 使两个链表后续的长度相同;两指针 再一起遍历(指针.next),边判断两个节点是否相等,相等则为第一个相交的节点。时间复杂度O(m+n),空间复杂度O(1)。
function getIntersectionNodeByLength(headA, headB){let lenA = 0, lenB = 0;let pA = headA, pB = headB;while(pA) { lenA++; pA = pA.next; }while(pB) { lenB++; pB = pB.next; }pA = headA;pB = headB;if(lenA > lenB){for(let i = 0;i < lenA - lenB; i++) pA = pA.next;}else{for(let i = 0;i < lenB - lenA; i++) pB = pB.next;}while(pA && pB && pA !== pB){pA = pA.next;pB = pB.next;}return pA;
}
参考:判断两个单链表是否相交及找到第一个交点_判断两个链表是否相交并找出交点-CSDN博客
图解LeetCode——160. 相交链表一、题目 给你两个单链表的头节点 headA 和 headB ,请你找出并返回 - 掘金
