给定两个单链表的头节点 headA
和 headB
,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。
图示两个链表在节点 c1
开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 输出:Intersected at '8' 解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。 在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
示例 2:
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 输出:Intersected at '2' 解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。 从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。 在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 输出:null 解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。 由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。 这两个链表不相交,因此返回 null 。
提示:
listA
中节点数目为m
listB
中节点数目为n
0 <= m, n <= 3 * 104
1 <= Node.val <= 105
0 <= skipA <= m
0 <= skipB <= n
- 如果
listA
和listB
没有交点,intersectVal
为0
- 如果
listA
和listB
有交点,intersectVal == listA[skipA + 1] == listB[skipB + 1]
此题因为是链表,所以两个链表一旦相交,就意味着交点的地址是一样的,并且其后面的节点的地址也都是一样的
两种思路:
思路1:(暴力求解)
依次取A链表中的每一个节点与B链表中的每一个节点进行比较,如果有地址相同的节点,则返回该节点;如果遍历完A链表中的所有节点都没有找到相交节点,则返回null;
思路2:
尾结点相同就是相交,尾结点不同,就不相交
求交点:长的链表先走(长度差)步,再同时走,第一个相同的就是交点
以下代码为思路二的方法:
因为要考虑到两个链表在相交前有可能长度不一样,所以我们要判断哪个链表长,长多少,让长的链表先走相差的步数,然后在一起走。
这里用到了一个abs的函数求差值的绝对值。
对于判断哪个链表长,这里用了一个巧方法:
先假设A链表为长链表,B链表为短链表,然后判断A链表与B链表的长度,如果A链表长度小于B链表的长度,那就假设错误,将B链表重新改为长链表,A链表重新改为短链表,后面便只要用长链表和短链表来用就行了。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
//找尾部节点,求长度
struct ListNode * tailA = headA;
int lenA = 1;
struct ListNode * tailB = headB;
int lenB = 1;
while (tailA->next)
{
lenA++;
tailA = tailA->next;
}
while (tailB->next)
{
lenB++;
tailB = tailB->next;
}
//判断是否相交
if (tailA != tailB)
{
return NULL;
}
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;
}
测试函数:
void test(struct ListNode* plist1, struct ListNode* plist2)
{
struct ListNode* inter_node = getIntersectionNode(plist1, plist2);
if (inter_node)
{
printf("相交节点为:%d\n", inter_node->val);
}
else
{
printf("两个链表没有交点\n");
}
}