题目:输入两个链表,找出它们的第一个公共结点。
当不存在公共节点时,返回空节点。
数据范围:链表长度 [1,2000]。保证两个链表不完全相同,即两链表的头结点不相同。
**样例**
给出两个链表如下所示:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3输出第一个公共节点c1
算法一:O(n)
1.算出两链表的长度,求出长度差lenA-lenB
2.都从头开始走,让较长的链表先走两个链表长度之差的步数
3.然后两链表一起走,相遇的结点即为第一个公共结点
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution {
public:
ListNode* findFirstCommonNode(ListNode* headA, ListNode* headB) {
int lenA = 0;
int lenB = 0;
for (ListNode* p = headA; p; p = p->next)lenA++;
for (ListNode* p = headB; p; p = p->next)lenB++;
int i = 0;
ListNode* pa = headA;
ListNode* pb = headB;
if (lenA > lenB)
{
i = lenA - lenB;
while (i--)
{
pa = pa->next;
}
}
else
{
i = lenB - lenA;
while (i--)
{
pb = pb->next;
}
}
while (pa || pb)
{
if (pa == pb)
return pa;
pa = pa->next;
pb = pb->next;
}
return NULL;
}
};
int main()
{
ListNode* A1 = new ListNode(2);
ListNode* A2 = new ListNode(4);
ListNode* A3 = new ListNode(6);
ListNode* A4 = new ListNode(8);
ListNode* B1 = new ListNode(1);
A1->next = A2;
A2->next = A3;
A3->next = A4;
B1->next = A3;
for (ListNode* p = A1; p; p = p->next)
{
cout << p->val << " ->";
}
cout << endl;
for (ListNode* p = B1; p; p = p->next)
{
cout << p->val << " ->";
}
cout << endl;
Solution s;
cout << s.findFirstCommonNode(A1, B1)->val << endl;
}
算法二:双指针O(n)
1. 用两个指针 p,q 分别指向两个链表 headA,headB 的头结点,同时向后遍历。
2. 当指针到达链表末尾时,重新定位到另一个链表的头结点。
3. 当它们相遇时,所指向的结点就是第一个公共结点。
算法证明:
证明:若有公共结点,相遇时(即公共结点):
p走的长度为a+c+b = q走的长度是b+c+a
若没有公共结点,且都走到对方链表的尾部(即p=q=nullptr)
p走的长度为a+b = q走的长度是b+a
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
ListNode* p=headA;
ListNode* q=headB;
while(p!=q)
{
if(p!=nullptr) p=p->next;//p先在headA链表上走
else //p如果走到headA尾结点,则再从headB链表起点开始走
p=headB;
if(q!=nullptr) q=q->next;
else
q=headA;
}
return p;//return q
}
};