Intersection of Two Linked Lists
Write a program to find the node at which the intersection of two singly linked lists begins.
For example, the following two linked lists:
A: a1 → a2 ↘ c1 → c2 → c3 ↗ B: b1 → b2 → b3
begin to intersect at node c1.
Notes:
- If the two linked lists have no intersection at all, return
null
. - The linked lists must retain their original structure after the function returns.
- You may assume there are no cycles anywhere in the entire linked structure.
- Your code should preferably run in O(n) time and use only O(1) memory.
解题思路:
1、最naive的办法,就是最每个a的指针,在b里面找,是否与之相同,若找到,则返回,否则返回NULL。这个办法时间复杂度为O(n*m)。不符合要求。
2、可以考虑用set来存储a的每个指针,然后针对每个b的指针,在set中查找。因为set中的查找可以看成是O(1)的,因此时间复杂度为O(n)。但是空间复杂度为O(n),不符合要求。
3、我的办法是,先分别扫描一遍a、b,记录a、b的长度为aLen,bLen。然后从头分别开始扫描,每扫描一个aLen--或bLen--,然后a或b向后移一个。具体是a移呢还是b移呢?这要看aLen大还是bLen大。具体代码如下,代码具有自解释:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
int aLen = 0, bLen = 0;
ListNode *p, *q;
p=headA;
while(p!=NULL){
aLen++;
p=p->next;
}
p=headB;
while(p!=NULL){
bLen++;
p=p->next;
}
ListNode* result=NULL;
p=headA;
q=headB;
while(p!=NULL&&q!=NULL){
if(p==q){
result=p;
break;
}else{
if(aLen>bLen){
p=p->next;
aLen--;
}else if(aLen<bLen){
q=q->next;
bLen--;
}else{
p=p->next;
q=q->next;
aLen--; //这里减不减都无所谓
bLen--;
}
}
}
return result;
}
};
4、看了一下官方的说法,先分别用两个指针pa,pb扫描,先到结尾的序列短(假设为b),将pb指向a的头,继续逐个扫描,当pa到达尾部后,将pa指向b的头。此时pa指向了b的头,pb指向了a中的某个节点,且pb后面未扫描的元素个数等于b链表的长度。此时再分别扫描,遇到pa=pb,则返回。下面是代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* pA=headA, *pB=headB;
while(pA!=NULL&&pB!=NULL){
if(pA==pB){
return pA;
}
pA=pA->next;
pB=pB->next;
}
if(pA==NULL){ //B比A长
pA=headB;
}else{
pB=headA;
}
while(pA!=NULL&&pB!=NULL){
pA=pA->next;
pB=pB->next;
}
if(pA==NULL){ //与之前第20步相反
pA=headB;
}else{
pB=headA;
}
while(pA!=NULL&&pB!=NULL){
if(pA==pB){
return pA;
}
pA=pA->next;
pB=pB->next;
}
return NULL;
}
};
上述3、4其实效率是一样的,都分别扫描了两次链表。4可能更快一点,但是方法没有很明白,不容易懂。提交后,发现很多人都比我的效率高呀,不知各位有更好的办法木有?