题目
编写一个程序,找到两个单链表相交的起始节点。
例如,下面的两个链表:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
在节点 c1 开始相交。
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
分析
题目重点在于要求满足时间复杂度是O(n)以及空间复杂度O(1)。
空间角度:由于需要遍历链表,那么一定需要游标指针,因此,不能够开辟更多的空间;
时间角度:难点在于如何保证时间是O(n)。因为两个链表的长度不一致,因此,在出现交点之前的节点数量不一致,因此,不能够通过逐个比较的方式。如果采取暴力的方式比较,那么一定是两层循环,则时间不满足要求。
关键问题在于出现交点之前两个链表的节点数不一致。
存在一个trick就是,假设两个链表的游标记为pA和pB,那么只要pA和pB都经历一遍链表1前面的节点以及链表2前面的节点,那么两个游标就会在交点处相遇。就好比整数求和中(2+3)+3 = (3+2)+3,两个游标走过的路径长度都是8。
以上面的例子为例,当pA走到c3的时候,pB走到C2,此时,只要让pA指向b1,当pB到尾部的时候,指向a1,那么pA和pB就会在c1处相遇。
另外,需要考虑,如果没有交点,那么按照上面的方式,两个游标将不断进行下去,因此,解决的方法是设定一个计数器count。如果两个链表存在交点,那么pA触碰一次表1尾,pB触碰一次表2尾一定会找到交点,如果某一个游标触发了第三次尾部,那么一定不存在交点。
算法
- 特殊情况1,两个表的头节点中有一个是空,那么没有交点;
- 特殊情况2,如果头指针相等,那么交点就是头指针;
- 当pA不等于pB的时候循环,设置计数器count=0;
- 如果pA->NULL,pA指向表2的head,count++,否则pA=pA->next;
- 如果pB->NULL,pB指向表1的head,count++,否则pB=pB->next;
- 最后退出循环,如果pA==pB,则是交点,返回,否则没有找到交点,返回NULL。
C++程序
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
//有一个列表为空,则交点为空
if(headA==NULL||headB==NULL){
return NULL;
}
//头节点就相等
if(headA==headB) return headA;
ListNode* pA = headA, *pB = headB;
int count = 0;
while(pA!=pB&&count<3){
if(pA->next==NULL) {
pA = headB;
count++;
}
else pA = pA->next;
if(pB->next==NULL){
pB = headA;
count++;
}
else pB = pB->next;
}
if(pA==pB) return pA;
else return NULL;
}