题目描述:
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
。
图示两个链表在节点 c1
开始相交:

方法:双指针
思路
-
定义两个尾指针,遍历找到两个链表的尾结点,同时计算链表长度
-
比较尾结点的地址,相同说明相交;不相同说明不相交
-
如果相交,定义长指针先移动差距步,把长短指针置于同一位置
-
然后遍历同时开始链表,第一个地址相等的结点,即为起始结点
示意图:
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
struct ListNode* tailA = headA;
struct ListNode* tailB = headB;
int lenA = 1;
int lenB = 1;
//找到尾结点
//遍历链表A,找尾结点,计算长度
while(tailA->next)
{
tailA = tailA->next;
lenA++;
}
//遍历链表A,找尾结点,计算长度
while(tailB->next)
{
tailB = tailB->next;
lenB++;
}
//比较两个尾结点的地址
//链表相交
if(tailA == tailB)
{
//找到起始结点
int gap = abs(lenA-lenB);
//找到长链表
struct ListNode* longList = headA;
struct ListNode* shortList = headB;
if(lenA < lenB)
{
longList = headB;
shortList = headA;
}
//把两个链表置于同一位置
while(gap--)
{
longList = longList->next;
}
//两个链表从同一位置开始遍历
while(longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
//返回起始结点
return longList;
}
//链表不相交
else
{
return false;
}
}
复杂度分析
- 时间复杂度:O(N+M),N是链表A结点总数,M是链表B结点总数,
- 链表不相交,尾指针tailA和tailB各自遍历一次链表,O(N+M)
- 链表相交
- 两次找尾,O(N+M)
- 找起始结点,最坏情况,在尾结点相交,O(N+M)
- 空间复杂度:O(1),函数getIntersectionNode运行过程中,只开辟了常数个变量空间,没有额外再开辟空间
总结
- 本文介绍了一种使用双指针方法来寻找两个单链表相交的起始节点的解决方案。
- 通过定义两个尾指针,遍历找到两个链表的尾结点,并同时计算链表的长度。
- 然后比较尾结点的地址,如果相同则说明链表相交,接下来将长指针先移动差距步,使得两个链表的指针处于相同位置,
- 然后同时遍历两个链表并找到第一个地址相等的节点,该节点即为相交链表的起始节点。
- 如果尾结点的地址不相同,则说明两个链表不相交。
- 该方法的时间复杂度为O(N+M),其中N和M分别是两个链表的结点总数。并且该方法的空间复杂度为O(1)。