题目
在本题中, 单链表可能有环, 也可能无环。 给定两个单链表的头节点 head1和head2, 这两个链表可能相交, 也可能不相交。 请实现一个函数, 如果两个链表相交, 请返回相交的第一个节点; 如果不相交, 返回null 即可。 要求: 如果链表1的长度为N, 链表2的长度为M, 时间复杂度请达到 O(N+M), 额外空间复杂度请达到O(1)
分析
这道题涵盖了链表相交的一系列问题 也是左老师直播课的内容,我们可以拆分成几个问题来分步处理,
- 首先判断单链表是否有环,这里我们给该函数增加一个功能,如果有环则返还该链表的入口结点,没有则返回NULL.
- 判断两个无环链表是否相交,如果相交则返回相交节点,否则返回NULL。
- 判断两个有环链表是否相交,如果相交则返回相交节点,否则返回NULL。
- 如果一个链表有环,一个无环则则不相交返回NULL;
问题一
采用快指针慢指针的方法,具体操作是,定义一个快指针和一个慢指针,从头结点开始,快指针一次走两步,慢指针一次走一步,(如果走到某一步快指针为NULL,说明它到头了,进而说明它没形成环,返回NULL)如果快指针和 慢指针相遇了,说明是有环的,此时让快指针从新回到头结点,并且调整步伐为每一一步,和慢指针同步,当它们再次相遇时,所处的位置就是入环结点,这就是个套路,知道这么用就好了。这部分代码如下:
Node*getNode(Node*head)
{
if (head == NULL)
return NULL;
Node*slow = head->next;
Node*fast = head->next->next;
while (fast != slow) {
if (fast->next == NULL || fast->next->next == NULL)
{
return NULL;
}
fast = fast->next->next;
slow = slow->next;
}
fast = head;
while (fast != slow)
{
fast = fast->next;
slow = slow->next;
}
return fast;
}
问题二
两个无环链表相交,结构就是一个Y字形,我们将两个链表各自遍历一遍,求出长度相减,就知道两个链表的相差长度,让长链表独自走相差出来的长度的距离,然后此时两个链表在同一起跑线了,同时往下走,直到结点相等,也就是他们首次相遇的地方。
Node*noLoop(Node*head1, Node*head2)
{
int n = 0;
Node*n1 = head1;
Node*n2 = head2;
while (n1 != NULL)
{
n++;
n1 = n1->next;
}
while (n2 != NULL)
{
n--;
n2 = n2->next;
}
n1 = n > 0 ? head1 : head2;
n2 = n1 == head1 ? head2 : head1;
n = abs(n);
while (n!=0)
{
n--;
n1 = n1->next;
}
while (n1 != n2)
{
n1 = n1->next;
n2 = n2->next;
}
return n1;
}
问题三
两个有环链表 一共三种形态:
可以通过入口结点是否相等当做边界条件来分析,当loop1=loop2时是图2的情况,跟两个无环链表相交的情况基本一致,有一点注意就是遍历链表求长度时只需要求到入口结点的长度,将下面的环砍掉,剩下的就和问题二一致。
当loop2不等于loop1时有可能是图一也有能是图二,这时让loop1结点往下遍历,并每次查看是否能等于loop2如果有等于说明是图3这时返回loop1或者loop2都可以,如果走了一圈还没碰到lloop2,说明是图1没有相交返回NULL;
Node*loop(Nod