本博客主要记录两个解法:
1.求两个单链表的节点个数,消除结点个数不同带来的影响,两个指针一起走,相遇即相交点。
2.数学方式求解。
一、求结点个数,消除结点个数不同带来的影响,俩指针同步走
思路:两个单链表相从相交的第一个结点开始,后面的结点都共享,所以两个单链表的节点个数之差就是相交的结点之前,两个单链表的结点个数之差,我们只需要将两个单链表结点个数之差算出来,然后消除结点个数不同带来的影响,让p1和p2同时向后走,那么相遇的时候,即相交的第一个结点,如下图:
p1和p2分别从两个单链表的如下位置同时向后走,那么p1和p2相遇时的结点即为相交的第一个节点(如果不相交,那么p1和p2最终都会指向NULL)
代码:
//不相交,返回NULL,相交返回第一个相交的结点
ListNode* FindTheSameNode(ListNode* head1, ListNode* head2)
{
if (head1 == NULL || head2 == NULL)//两个单链表都是空的
{
return NULL;
}
ListNode* p1 = head1;
int num1 = 0;//记录第一个单链表的节点个数
ListNode* p2 = head2;
int num2 = 0;//记录第二个单链表的结点个数
while (p1 != NULL)//计算第一个单链表的节点个数
{
++num1;
p1 = p1->next;
}
while (p2 != NULL)//计算第二个单链表的节点个数
{
++num2;
p2 = p2->next;
}
p1 = head1;
p2 = head2;
//让p1或者p2把节点个数的差值的影响去除
while (num1 > num2)
{
p1 = p1->next;
num1--;
}
while (num2 > num1)
{
p2 = p2->next;
num2--;
}
while (p1 != p2)//如果相交,则退出时p1 == p2,指向"相交的第一个结点",如果不相交,则最后p1 == p2 == NULL
{
p1 = p1->next;
p2 = p2->next;
}
return p1;
}
二、数学思维
思路:
如下图,假设相交的结点之前第一个单链表的结点个数为a,第二个结点个数为b,相交部分结点个数为c
那么p1(==head1)走完整个单链表,走的距离为:a+c
那么p2(==head2)走完整个单链表,走的距离为:b+c
如果我们让p1走单链表的尾之后,从head2继续向后走,p2走到单链表的尾之后从head1继续向后走,那么最后p1和p2到相交的第一个结点一定相遇,因为它们俩这个时候走的总距离都为a+b+c+1,一起走的,所以p1和p2在单链表相交的第一个结点的位置一定相遇。如果单链表没有相交,那么最后p1和p2都会指向NULL。
代码:
ListNode* FindTheSameNode(ListNode* head1, ListNode* head2)
{
if (head1 == NULL || head2 == NULL)
{
return NULL;
}
ListNode* p1 = head1;
ListNode* p2 = head2;
while (p1 != p2)
{
p1 = p1 == NULL ? head2 : p1->next;
p2 = p2 == NULL ? head1 : p2->next;
}
return p1;//如果head1和head2相交,则p1(p2)为第一个相交的结点,如果不相交,那么p1 == p2 == NULL
}