题目:
输入两个链表,找出它们的第一个公共结点。
解题思路:
分为有环链表相交与无环链表相交问题,一个有环一个无环的链表相交情况不存在。
1、判断两个链表是否有环,有环返回入环节点,无环返回NULL;
2、两个无环链表->noLoop判断是否相交
1)末节点不一致一定不相交
2)末节点一致,长链表先遍历差值个节点,后同步遍历,第一个相等节点即为目标节点
3、两个有环链表->bothLoop判断是否相交
1)判断拓扑类型
2)针对不同拓扑分情况判别:
(a)入环节点一致,从入环节点之前为无环链表相交的判定;
(b)入环节点不一致,从loop1遍历发现loop2节点,则两个链表相交,返回loop1和loop2均可;
©入环节点不一致,从loop1节点遍历未发现loop2节点,则两个有环链表不相交。
代码实现
1、主函数
#include<iostream>
using namespace std;
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) {
if (pHead1 == NULL || pHead2 == NULL)
{
return NULL;
}
ListNode* loop1 = getLoopNode(pHead1);
ListNode* loop2 = getLoopNode(pHead2);//找到入环节点
if (loop1 == NULL && loop2 == NULL)
{
return noLoop(pHead1, pHead2);
}
if (loop1 != NULL && loop2 != NULL)
{
return bothLoop(pHead1, loop1, pHead2, loop2);
}
return NULL;//一个有环一个无环不可能相交
}
2、获取入环节点函数
ListNode* getLoopNode(ListNode* pHead)
{
if (pHead == NULL || pHead->next == NULL || pHead->next->next == NULL)
{
return NULL;//不构成环
}
ListNode* pSlow = pHead;
ListNode* pFast = pHead->next->next;//快慢指针
while (pSlow != pFast)//有环链表快指针必定在环上追上慢指针
{
if (pFast == NULL)
{
return NULL;//快指针走到空节点说明一定无环
}
pFast = pFast->next->next;
pSlow = pSlow->next;
}
pFast = pHead;//追上后,快指针调至头结点,与慢指针同步前进,必定在如环节点相遇
while (pSlow != pFast)
{
pSlow = pSlow->next;
pFast = pFast->next;
}
return pSlow;
}
3、无环链表相交函数
ListNode* noLoop(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == NULL || pHead2 == NULL)
{
return NULL;
}
ListNode* p1 = pHead1;
ListNode* p2 = pHead2;
int n1 = 1;
int n2 = 1;
while (p1->next != NULL)
{
n1++;
p1 = p1->next;
}
while (p2->next != NULL)
{
n2++;
p2 = p2->next;
}
//p1和p2走到末节点
if (p1 != p2)
{
return NULL;//末节点不相等则不相交
}
p1 = n1 > n2 ? pHead1 : pHead2;//p1为长链表
p2 = p1 == pHead1 ? pHead2 : pHead1;//p2为短链表
int n = n1 > n2 ? n1 - n2 : n2 - n1;//长度差值
while (n != 0)
{
n--;
p1 = p1->next;//长链表先走差值长度
}
while (p1 != p2)
{
p1 = p1->next;
p2 = p2->next;//同步行进,相交点点处相遇
}
return p1;
}
4、有环链表相交函数
ListNode* bothLoop(ListNode* pHead1, ListNode* loop1, ListNode* pHead2, ListNode* loop2)
{
ListNode* p1 = NULL;
ListNode* p2 = NULL;
if (loop1 == loop2)//结构(a),如环节点一致的相交有环链表
{
p1 = pHead1;
p2 = pHead2;
//以下类似于无环链表相交的判定
int n1 = 1;
int n2 = 1;
while (p1 != loop1)//改为入环节点前的相交判定
{
n1++;
p1 = p1->next;
}
while (p2 != loop2)
{
n2++;
p2 = p2->next;
}
p1 = n1 > n2 ? pHead1 : pHead2;//p1为长链表
p2 = p1 == pHead1 ? pHead2 : pHead1;//p2为短链表
int n = n1 > n2 ? n1 - n2 : n2 - n1;//长度差值
while (n != 0)
{
n--;
p1 = p1->next;//长链表先走差值长度
}
while (p1 != p2)
{
p1 = p1->next;
p2 = p2->next;//同步行进,相交点点处相遇
}
return p1;
}
else
{
p1 = loop1->next;
while (p1 != loop1)
{
if (p1 == loop2)//在回到环起点前遇到loop2,(b)结构
{
return loop1;//默认返回loop1
}
p1 = p1->next;
}
return NULL;//结构(c)
}
}
整理略有匆忙,如有问题欢迎指正共同探讨。