题目
输入两个链表,找出它们的第一个公共结点。
当不存在公共节点时,返回空节点。
样例
给出两个链表如下所示:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
输出第一个公共节点c1
方法一题解
1. 用两个指针 p1,p2 分别指向两个链表的头结点 headA,headB ,同时向后遍历。
2. 当其中一个指针到达该指针所指链表末尾(NULL)时,重新将这个指针定位到另一个链表的头结点。(两个指针交替进行一次同样的操作)
3. 当它们相遇时,所指向的结点就是第一个公共结点。
图示解释
设A链表的非公共部分长度为LA,B链表的非公共部分长度为LB,公共部分长度为C。
A链表总长度为LA + C,B链表总长度为LB + C。
当指针按照题解方式走下去,p1第二次走到公共节点的时候,走过的长度为LA + C + LB,p2第二次走到公共节点的时候,走过的长度为LB + C + LA。p1 和 p2走过的长度相等,p1、p2 必会相遇。
所以,当p1 和 p2 相遇(相等)的时候,指向的节点就是公共节点。
全过程图解
C++代码(1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
ListNode *p1, *p2;
p1 = headA;
p2 = headB;
int count = 2; //两次经过公共结点
if(p1==NULL || p2==NULL) //判空
{
return NULL;
}
while(count)
{
while(p1!=NULL && p2!=NULL)
{
p1 = p1->next;
p2 = p2->next;
}
if(p1 == NULL)
{
p1 = headB;
}
if(p2 == NULL)
{
p2 =headA;
}
count--;
}
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
};
更简洁的写法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA;
ListNode *p2 = headB;
while (p1 != p2) {
if(p1 != NULL)//p1没有走到结尾
p1 = p1->next;//p1指向下一个节点
else //p1走到结尾
p1 = headB;//p1指向另一个链表头
if(p2 != NULL)//p2没有走到结尾
p2 = p2->next;//p2指向下一个节点
else //p2走到结尾
p2 = headA;//p2指向另一个链表头
}
return p1;
}
};
方法二题解
如果有公共结点,肯定是两个链表在后面重叠,且后面部分都是共同的。
那么,可以先计算出两个链表的长度,然后通过两个指针让比较长的链表先走(先遍历)两个链表长度之差的步数,最后两个再一起走(一起遍历),最终两个指针一定会相遇。
C++代码(2)
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
ListNode *p1 = headA;
ListNode *p2 = headB;
if(!p1 || !p2)
return NULL;
int len1 = 0, len2 = 0;
while(p1)
{
len1++;
p1 = p1->next;
}
while(p2)
{
len2++;
p2 = p2->next;
}
if(len1 == len2)
{
p1 = headA;
p2 = headB;
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
else
{
if(len1 > len2)
{
p1 = headA;
p2 = headB;
int len = len1 -len2;
while(len)
{
p1 = p1->next;
len--;
}
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
else
{
p1 = headA;
p2 = headB;
int len = len2 -len1;
while(len)
{
p2 = p2->next;
len--;
}
while(p1 != p2)
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
}
}
};