160题 相交链表/找出两个链表的交点
难度:简单Easy
题目描述:
给定如下面的两个链表:
在节点 c1 开始相交。
注意:
- 如果两个链表没有交点,返回 null.
- 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
- 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
思路
idea: 双指针法(two pointers)
定义两个指针pA和pB,用pA指向链表A的开头,pB指向链表B的开头,链表A的长度为a+c,链表B的长度为b+c,其中c为重复的部分
e.g
链表A: 1->2->3->4->5->6->null
链表B: 9->5->6->null, 交点为5
还有可能公共的部分只有一个null
e.g
链表A: 1->2->3->4->5->6->null
链表B: 7->8->9->null, 交点为null
当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。
把A看成主链表,B看成辅链表.当pB指针走完链表B回到链表A的开头时,相当于pA指针比pB指针多走了链表B的长度;同理,当pA在链表A走完后又在链表B走完时,相当于pA又让了pB共链表B的长度.最终两个指针一定是一起走到终点.此时 a + c + b = b + c + a
如果两个链表最后的部分是重合的话,则两个指针会在第一个重合的节点相遇,不会等到最后,因为此时已不满足while(pA!=pB)
若两个链表没有交点,则两个指针都会走到各自链表的结尾null,此时满足(pA = pB = null),此时 a + b = b + a
可以理解成两个人速度一致, 走过的路程一致。那么肯定会同一个时间点到达终点。如果到达终点的最后一段路两人都走的话,那么这段路上俩人肯定是肩并肩手牵手的。如果没有相交点,则会在最后相遇。
代码:
Java
class Solution{
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) return null;
ListNode pA = headA, pB = headB; // 指针pA指向链表1的开头,指针pB指向链表2的开头
while (pA != pB) {
pA = (pA == null) ? headB : pA.next;
pB = (pB == null) ? headA : pB.next;
}
return pA; // 若有交点,则返回第一个相交的点,若没有,返回末尾null
}
}
C++
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *pA = headA, *pB = headB;
// 若有交点,则走到第一个交点的时候跳出while循环; 若没有交点,则走到结尾null时跳出while循环
while (pA != pB) {
pA = pA ? pA->next : headB; // 若pA不存在,即pA走到头了,则从pB继续开始
pB = pB ? pB->next : headA; // 若pB存在,表示还没走到尾部,pB继续向前走
}
return pA;
}
};
总结
把链表A看成主链表,链表B看成辅链表,当pB指针走完链表B回到链表A的开头时,相当于pA指针比pB指针多走了链表B的长度;同理,当pA在链表A走完后又在链表B走完时,相当于pA又让了pB共链表B的长度。最终两个指针一定是一起走到终点。如果两个链表最后的部分是重合的话,则两个指针会在第一个重合的节点相遇,不会等到最后,因为此时已不满足
while(pA != pB)