一、需求
- 输入两个链表,找出它们的第一个公共节点。
- 如下面的两个链表:
- 在节点 c1 开始相交。
二、双指针(暴力)
2.1 思路分析
- 采用双重循环,使用两个指针p、q分别指向链表A和链表B,外循环遍历链表A,内循环遍历链表B,每次判断当前链表A的节点是否就是当前链表B的节点,如果是就返回该节点,否则就一直遍历,直到链表A遍历结束;
- 如果不存在公共结点,则返回null;
- 因为本题要求时间复杂度限制在O(1),故该方法在运行时会出现超时;
2.2 代码实现
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p = headA;
while(p != null) {
ListNode q = headB;
while(q != null) {
if(p == q) return p;
q = q.next;
}
p = p.next;
}
return null;
}
}
2.3 复杂度分析
- 时间复杂度为O(n^2),因为采用了双重循环,计算次数为n^2;
- 空间复杂度为O(1),变量p,q占用常数大小的额外空间;
三、双指针法(优化)
3.1 思路分析
- 假设链表A、B存在公共节点,链表A头节点距离公共节点为L1步,即[A头节点,公共节点),链表B头节点距离公共节点为L2步,即[B头节点,公共节点),两个链表的公共部分长度为C;
- 那么根据L1+C+L2 = L2+C+L1的原理,设指针p,q指向链表A,B,p,q同时移动,当p走过L1+C+L2后,q走过L2+C+L1后,它们会在公共结点相遇;
3.2 代码实现
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p = headA;
ListNode q = headB;
while(p != q) {
//这里让双指针同时移动,避免了循环
p = p != null ? p.next : headB;
q = q != null ? q.next : headA;
}
return p;
}
}
3.3 复杂度分析
- 时间复杂度为O(n);
- 空间复杂度为O(1);
四、学习地址
作者:腐烂的橘子