题目描述
输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
代码
ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
//方法一:对pHead1中的每个结点都去遍历一遍pHead2,比较两者的结点,若有相同的则证明相交,时间复杂度为O(len1*len2)
#if 0
ListNode* s1 = pHead1;
ListNode* s2 = pHead2;
bool same = false;
while (s1 != NULL)
{
s2 = pHead2;
while (s2 != NULL)
{
if (s1 == s2)
{
same = true;
break;
}
s2 = s2->next;
}
if (same)
{
return s1;
}
s1 = s1->next;
}
return NULL;
#endif
//方法二:利用哈希缓存:先将pHead1中的每个结点都存入哈希表中,然后对pHead2中的每个结点去哈希表中找。时间复杂度为:O(max(len1+len2);但同时还得增加O(len1)的存储空间存储哈希表
#if 0
unordered_set<ListNode*> myset;
ListNode* s1 = pHead1;
ListNode* s2 = pHead2;
while (s1 != NULL)
{
myset.insert(s1);
s1 = s1->next;
}
while (s2 != NULL)
{
bool flag = false;
if (myset.find(s2) == myset.end())//没有找到相同的结点
{
flag = false;
}
else
{
flag = true;
return s2;//找到了相同的结点
}
s2 = s2->next;
}
return NULL;
#endif
//方法三:遍历两次链表,时间复杂度为O(len1+len2)。
#if 0
/*
首先,公共结点是指两个链表从某个结点开始,next指向同一个结点。但由于单向链的每个结点只有一个next,因此从第一个公共结点开始,
两个链表之后的结点都是重合的。
对于两个没有环的链表相交于一节点,则在这个节点之后的所有结点都是两个链表所共有的。
如果它们相交,则最后一个结点一定是共有的,则只需要判断最后一个结点是否相同即可。
如何找到相交的第一个结点,
求出两个链表的长度,然后用长的减去短的得到一个差值 K,然后让长的链表先遍历K个结点,
然后两个链表再同时出发,相遇的第一个结点就是第一个公共结点。
*/
//保存两个链表的最后一个结点进行比较
ListNode* s1 = pHead1;
ListNode* s2 = pHead2;
bool flag = false;
int lengthofs1 = 0;//链表1的长度
int lengthofs2 = 0;//链表2的长度
while (s1 != NULL)
{
lengthofs1++;
if (s1->next == NULL)
{
while (s2!=NULL)
{
lengthofs2++;
if (s2->next == NULL)//遍历到了s2的最后一个结点
{
if (s1 == s2)
{
flag = true;
break;
}
}
s2 = s2->next;
}
}
if(flag)
break;
s1 = s1->next;
}
if (flag)//求出第一个公共结点
{
int k = 0;
s1 = pHead1;
s2 = pHead2;//重新指向头结点
if (lengthofs1 > lengthofs2)//链表1长
{
k = lengthofs1 - lengthofs2;
int cont = 0;//记录第二次遍历的长度
while (s1 != NULL && cont < k)
{
cont++;
s1 = s1->next;
}
while (s1 != NULL && s2 != NULL)
{
if (s1 == s2)
return s1;
s1 = s1->next;
s2 = s2->next;
}
}
else
{
k = lengthofs2 - lengthofs1;//链表2长
int cont = 0;//记录第二次遍历的长度
while (s2 != NULL && cont < k)
{
cont++;
s2 = s2->next;
}
while (s1 != NULL && s2 != NULL)
{
if (s1 == s2)
return s1;
s1 = s1->next;
s2 = s2->next;
}
}
}
else
{
return NULL;//不存在公共结点
}
#endif
//方法四:使用两个指针,时间复杂度为O(max(len1+len2)
#if 1
/*
如果链表1和链表2的长度相等,则可以定义两个指针分别指向链表1和链表2,然后同时遍历,
在链尾之前有相同的结点则说明相交,并且第一个相同的结点就是公共结点。
现在是链表1和链表2的长度不相等,分别为len1、len2,len1!=len2,但len1+len2=len2+len1
即把链表2的长度加到链表1上(即链表1的开头是链表2的点),链表1的长度加到链表2上
*/
ListNode* s1 = pHead2;//链表1
ListNode* s2 = pHead1;//链表2
while (s1 != s2)
{
//if (s1 != NULL)//到最后一个结点
//{
// s1 = s1->next;
//}//把链表2的长度加到了链表1上
//else
//{
// s1 = pHead1;
//}
s1= s1? s1->next:pHead1 ;
s2 = s2? s2->next:pHead2;
}
return s1;
#endif
}