题目
给你两个单链表的头节点 headA 和 headB,找出并返回两个单链表相交的起始节点 。如果两个链表不存在相交节点,返回 null。
注意: 相交是指引用相同,不是值相同。
思路
这道题最巧妙的解法是双指针法,核心思想就一句话:
两个指针分别走完自己的路,然后走上对方的路,如果有交点,它们一定会在交点相遇。
为什么能相遇?
假设:
-
链表 A 的非公共部分长度为
a -
链表 B 的非公共部分长度为
b -
公共部分长度为
c
指针 A 走的路径:a + c + b
指针 B 走的路径:b + c + a
两条路径长度一样,如果有交点,它们在走完 a + b + c 步后一定同时到达交点。
如果没有交点,两个指针都会走完 a + b 步后同时变成 null,循环结束,返回 null。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode A = headA;
ListNode B = headB;
while (A != B) {
// A 走到头就切换到 B 的头
if (A == null) {
A = headB;
} else {
A = A.next;
}
// B 走到头就切换到 A 的头
if (B == null) {
B = headA;
} else {
B = B.next;
}
}
return A;
}
}
执行过程示例
A: 1 → 2 → 3 → 4
B: 6 → 3 → 4
| 步数 | 指针 A | 指针 B |
|---|---|---|
| 初始 | 1 | 6 |
| 1 | 2 | 3 |
| 2 | 3 | 4 |
| 3 | 4 | null → 切换到 headA |
| 4 | null → 切换到 headB | 1 |
| 5 | 6 | 2 |
| 6 | 3 | 3 ✅ 相遇,返回交点 |
关键点
| 细节 | 为什么 |
|---|---|
while (A != B) |
相等时要么都指向交点,要么都指向 null |
| 走完切换链表 | 保证两个指针走的路程一样长 |
比较的是引用 == |
题目说相交是引用相同,不是值相同 |
复杂度
-
时间复杂度:O(m + n),每个指针最多走 m + n + 1 步
-
空间复杂度:O(1),只用了两个指针
总结
这题的精髓在于:让两个指针走相同的路程,有交点必相遇,没交点同归 null。