1 题目
题目:两个链表的交叉(Intersection of Two Linked Lists)
描述:请写一个程序,找到两个单链表最开始的交叉节点。
- 如果两个链表没有交叉,返回null。
- 在返回结果后,两个链表仍须保持原有的结构。
- 可假定整个链表结构中没有循环。
lintcode题号——380,难度——medium
样例1:
输入:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
输出:c1
解释:在节点 c1 开始交叉。
样例2:
输入:
Intersected at 6
1->2->3->4->5->6->7->8->9->10->11->12->13->null
6->7->8->9->10->11->12->13->null
输出: Intersected at 6
解释:begin to intersect at node 6.
2 解决方案
2.1 思路
找链表交点的问题,可以将两个链表构造成一个带环链表,这样就可以参考寻找带环链表中的环的起点的做法,本题将任意一个链表的尾部连接到链表头,就能构造出一个带环的链表了。
2.2 图解
两个相交的链表:
将其中一个首尾相连,就可以构成一个大的带环链表:
2.3 时间复杂度
若两个链表的长度分别为m和n,时间复杂度为O(n)。
2.4 空间复杂度
空间复杂度为O(1)。
3 源码
细节:
- 连接其中一个链表a的首尾,形成环,将两个链表构成一整个链表,新链表的表头是链表b的表头。
- 按照寻找带环链表中的环的起点位置的做法,
C++版本:
/**
* Definition of singly-linked-list:
* class ListNode {
* public:
* int val;
* ListNode *next;
* ListNode(int val) {
* this->val = val;
* this->next = NULL;
* }
* }
*/
/**
* @param headA: the first list
* @param headB: the second list
* @return: a ListNode
*/
ListNode * getIntersectionNode(ListNode * headA, ListNode * headB) {
// write your code here
if (headA == nullptr || headB == nullptr)
{
return nullptr;
}
// 找到B链表的尾部
ListNode * cur = headB;
while (cur->next != nullptr)
{
cur = cur->next;
}
cur->next = headB; // 将B链表尾部连接到其头部形成环
// 在AB链表形成的链表环里寻找交点
ListNode * slow = headA;
ListNode * fast = headA;
while (fast != nullptr && fast->next != nullptr)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast) // 找到环,slow记录了快慢指针相遇的位置
{
ListNode * index = headA; // 新建一个从头开始的指针
while (index != slow) // index与slow同时前进,相遇的时候就是链表环的起点
{
index = index->next;
slow = slow->next;
}
cur->next = nullptr; // 将链表B复原
return index;
}
}
return nullptr; // 如果无环,则返回空
}