题目描述:
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
。
图示两个链表在节点 c1
开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
解题思路:
首先我们得明白,单链表只有一个next指针,如果两个单链表相交,那从相交结点开始,两链表完全相同,所以相交链表一定是Y字型的,不可能出现X型.,并且如果两链表最后一个结点不相同,则两链表一定不相交.
思路1:(暴力求解):
依次取第一个链表的一个结点与第二个链表的全部结点相比较(这里要注意比较的是结点的地址),若找到地址相同的结点,那么该结点就是相交结点,若遍历完第一个链表还没有找到,则表示两链表没有相交,其时间复杂度为O(n^2)
思路二:
如果相交链表是上如所示形状,那便可以取第一个链表的第一个结点与第二个链表的第一个结点比较,若不相同,继续比较两链表的第二个几点,直到找到相交结点.这样就可以把时间复杂度控制到O(n),这种方法虽然有效,但是碰到下图所示情况就没办法用了:
思考一下,如果两个链表相交的话,假设第一个链表在相交结点前有n个结点,第二个链表在相交结点前有m个结点,(假设n>m),那么第一个链表的前n-m个结点肯定不是相交结点.
所以就可以分别遍历两个链表并求出其长度,让较长的链表先走两链表长度的差值步,使两链表相交结点前的结点数相同,这样就可以用上面讲的思路了.
这里有两个小细节:
- 在求两链表的长度时,遍历链表的条件为 while(cur->next != NULL),这样遍历完成时cur指针指向的就是链表的最后一个结点,虽然这样写会导致求出来的链表长度少了1个结点,但是我们求两个链表的长度是为了知道其长度差,而两个链表长度都少1并不会影响结果
- 由于我们并不知道两个链表谁长谁短,可以使用 if 语句判断,如果第一个链表长就让第一个链表先走,如果第二个链表长就让第二个链表先走,但是这样写会有很多代码重复.这种情况就可以使用假设法,定义一个longlist指针和一个shortlist指针,我们先让longlist指向第一个链表,short指向第二个链表,我们在判断第一个链表的长度是否大于第二个链表的长度,如果不是,则让longlist指向第二个链表,shortlst指向第一个链表,这样longlist一定指向的是长度较长的链表,short一定指向的是长度较短的链表,后续我们只要操作longlist和shortlist就好了
参考代码:
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *curA=headA;
struct ListNode *curB=headB;
int lenA=0;
int lenB=0;
while(curA->next)
{
lenA++;
curA=curA->next;
}
while(curB->next)
{
lenB++;
curB=curB->next;
}
if(curA!=curB)
return NULL;
//假设长的链表为A
struct ListNode *longlist=headA;
struct ListNode *shortlist=headB;
if(lenA<lenB)
{
longlist=headB;
shortlist=headA;
}
int n=abs(lenA-lenB);
//先让长链表先走
while(n--)
{
longlist=longlist->next;
}
//两个链表同时走找相交结点
while(longlist!=shortlist)
{
longlist=longlist->next;
shortlist=shortlist->next;
}
return longlist;
//return shortlist;
}