文章目录
-
- 一、题目描述
- 二、示例讲解
-
- 示例一
- 三、思维导图
- 四、解法一:哈希表法
-
- 原理说明
- 流程图展示
- 时间与空间复杂度
- Java 实现
- 五、解法二:双指针法(推荐)
-
- 原理说明
- 示例演示
- 时间与空间复杂度
- Java 实现
- 六、总结
一、题目描述
给定两个单链表 headA 和 headB,找出并返回这两个链表相交的起始节点。如果两个链表没有交点,则返回 null。
链表可能具有 不同的长度,但如果它们相交,会在某个节点之后共享相同的尾部。
二、示例讲解
示例一
假设有如下两个链表:
ListA: 4 → 1
↘
8 → 4 → 5
↗
ListB: 5 → 6 → 1
它们在节点值为 8 的位置相交,输出应为该节点。
三、思维导图
使用 Mermaid 思维导图可视化题意与解题思路:
两个链表的相交节点
题目理解
两个单链表可能长度不等
若相交则共享尾部部分
否则返回null
解法思路
方法一:哈希表存储节点
方法二:双指针法
复杂度分析
n+m
空间复杂度 O(1) 或 O(n)
关键目标
找出第一个相交节点
四、解法一:哈希表法
原理说明
- 首先遍历链表 A,将所有节点加入哈希表。
- 然后遍历链表 B,每访问一个节点,检查是否在哈希表中出现过。
- 若出现,则该节点即为相交起点;若遍历完未出现,则返回
null。
流程图展示
是
否
开始
遍历链表A
将每个节点加入哈希表
遍历链表B
节点是否在哈希表中?
返回该节点
继续遍历
遍历结束返回null
时间与空间复杂度
-
时间复杂度:O(n + m)
其中
n和m分别为两个链表的长度。 -
空间复杂度:O(n)
因为需要使用额外哈希表存储链表 A 的节点。
Java 实现
java
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> visited = new HashSet<>();
ListNode currA = headA;
while (currA != null) {
visited.add(currA);
currA = currA.next;
}
ListNode currB = headB;
while (currB != null) {
if (visited.contains(currB)) {
return currB; // 找到相交节点
}
currB = currB.next;
}
return null; // 无相交点
}
}
五、解法二:双指针法(推荐)
原理说明
使用两个指针 pA 和 pB,分别从链表 A 和 B 的头开始遍历:
- 当一个指针到达链表尾端时,从另一条链表的头重新开始。
- 两个指针最终会在相交节点相遇,或同时到达
null(不相交)。
这种方法可以"抵消长度差"的影响,使得两个指针在第二次遍历时对齐。
示例演示
指针pB 指针pA 指针pB 指针pA pA 从 headA 开始,pB 从 headB 开始 遍历A 遍历B A到尾时跳到headB B到尾时跳到headA 最终相遇 → 相交节点
时间与空间复杂度
-
时间复杂度:O(n + m)
最多遍历两次链表。
-
空间复杂度:O(1)
仅使用两个指针,无额外存储。
Java 实现
java
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode pA = headA;
ListNode pB = headB;
while (pA != pB) {
pA = (pA == null) ? headB : pA.next;
pB = (pB == null) ? headA : pB.next;
}
return pA; // 可能为相交节点或null
}
}
六、总结
| 解法 | 思路 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|---|
| 哈希表法 | 存储链表A节点再遍历B查找 | O(n+m) | O(n) | 简单直观 | 额外空间消耗 |
| 双指针法 | 两指针交替遍历抵消长度差 | O(n+m) | O(1) | 空间最优、优雅 | 不易直观理解初见者 |