给出两个单链表的头结点headA与headB,让我们找出两个链表相接的起始节点,如果两个链表不存在相交结点返回null。
我们就先假设存在这样两个链表,链表1与链表2,假设链表1的长度为 L 1 L_1 L1和 L 2 L_2 L2,假设对于两个链表,从相交的结点向后数长度为 L 1 , 2 L_{1,2} L1,2,则在相交结点之前链表1的长度未 L 1 − L 1 , 2 L_1-L_{1, 2} L1−L1,2链表2的长度为 L 2 − L 1 , 2 L_2- L_{1, 2} L2−L1,2,对于两条链表无相交的情况 L 1 , 2 = 0 L_{1,2}=0 L1,2=0,如图是具有相交部分的两个链表的图示:
不相交的两个链表的图示你可以想象出来,将后面的那一部分去掉就行了。
我们现在想的就是如何让遍历链表1的指针与遍历链表2的指针能够相遇在同一节点,如图所示:
显然这两个链表在相交部分前面的部分可能不一样长也就是 L 1 ≠ L 2 L_1\neq L_2 L1=L2,也就是我们我们直接从头结点遍历遍历到尾结点是不行的,我们们来看一下遍历到尾节点之后链表1走了多远 ( L 1 − L 1 , 2 ) + L 1 , 2 (L_1-L_{1,2})+L_{1,2} (L1−L1,2)+L1,2链表2走过的长度为 ( L 2 − L 1 , 2 ) + L 1 , 2 (L_2-L_{1,2})+L_{1,2} (L2−L1,2)+L1,2是不是我们可以看出有一段是公共的长度,它们两个走过的长度不一样就不一样在 ( L 1 − L 1 , 2 ) (L_1-L_{1,2}) (L1−L1,2)与 ( L 2 − L 1 , 2 ) (L_2-L_{1,2}) (L2−L1,2)这两项上,如果说在链表1走过的路程加上一个 ( L 2 − L 1 , 2 ) (L_2-L_{1,2}) (L2−L1,2),在链表2走过的路程加上一个 ( L 1 − L 1 , 2 ) (L_1-L_{1,2}) (L1−L1,2),它们是不是就一样了,都为 ( L 1 − L 1 , 2 ) + L 1 , 2 + ( L 2 − L 1 , 2 ) (L_1-L_{1,2})+L_{1,2}+(L_2-L_{1,2}) (L1−L1,2)+L1,2+(L2−L1,2)
我们整理一下:
链表1走过的路程为: { ( L 1 − L 1 , 2 ) + L 1 , 2 } + ( L 2 − L 1 , 2 ) \{(L_1-L_{1,2})+L_{1,2}\}+(L_2-L_{1,2}) {(L1−L1,2)+L1,2}+(L2−L1,2)
链表2走过的路程为: ( L 1 − L 1 , 2 ) + { ( L 1 , 2 ) + ( L 2 − L 1 , 2 ) } (L_1-L_{1,2})+\{(L_{1,2})+(L_2-L_{1,2})\} (L1−L1,2)+{(L1,2)+(L2−L1,2)}
在这两个式子中,我们发现{}所围的为自己链表的长度,其余的为对方链表的在相交之前的部分的长度。也就是说如果我们遍历自身链表,到结尾之后再去遍历对方链表就能让两个指针同步。
两个指针同步之后,如果在同步之后后面仍有结点,则说明有相交部分,如果同步之后后面没有结点了,则说明这两个链表之间没有相交部分。
有了上面的思路,我们可以写出下面的代码:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *p=headA, *q=headB;
while(p!=q){
if(p==NULL){
p = headB;
}else{
p = p->next;
}
if(q==NULL){
q = headA;
}else{
q = q->next;
}
}
return p;
}
而且程序的时间复杂度为 O ( n + m ) O(n+m) O(n+m)空间复杂度为 O ( 1 ) O(1) O(1)
程序运行结果: