本文仅仅整理一下解题思路,没有代码供参考。
如何判断两个链表是否相交?
- 两个无环链表相交
- 两个链表都为有环情况
两个无环链表相交
大概就是一个Y字形
解法:
- 暴力解法
从头开始遍历一个链表,遍历第一个链表中的每个节点时,同时从头到尾遍历第二个链表,看是否有相同的节点,第一次找到相同的节点即第一个交点;若遍历结束未找到相同的节点,即不存在交点,时间复杂度为O(n^2) - 使用栈
我们可以从头遍历两个链表。创建两个栈,第一个栈存储第一个链表的节点,第二个栈存储第二个链表的节点,直至链表的所有节点入栈,通过取两个栈的栈顶元素节点判断是否相等即可判断两个链表是否相交。从第一个相交节点之后,后续节点均相交直至链表结束。出栈直至两个节点不相同时,则这个节点的后一个节点是第一个相交节点。 - 遍历链表记录长度
设链表A 的长度为 a + c,链表B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。
A、B链表 同时从头部出发。当访问链表 A 的指针访问到链表尾部时,令它从链表 B 的头部重新开始访问链表 B;同样地,当访问链表 B 的指针访问到链表尾部时,令它从链表 A 的头部重新开始访问链表 A。这样当访问到蓝色节点时,两个指针会同时指向蓝色节点(a+c+b=b+c+a)。
public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
ListNode l1 = pHead1, l2 = pHead2;
while (l1 != l2) {
l1 = (l1 == null) ? pHead2 : l1.next;
l2 = (l2 == null) ? pHead1 : l2.next;
}
return l1;
}
两个链表都为有环情况
如何判断一个链表有环
设置两个链表指针fast, slow,初始值都指向链表头结点,然后两个指针都往后走,不同的是slow每次前进一步,即前进一个节点。fast每次前进两步,如果存在环,两个指针必定相遇。
上图可以看出,当slow指针后移4次后会处在5号节点的位置。fast指针后移8次以后也会处在5号节点的位置。由此可以判断该链表是有环的。
若链表有环,找到环的入口点
从上图中可以知道链表有环,快慢指针一定相遇(不为空的相遇)。但是相遇点一定是入口点吗?
答案是不一定。
那么如果找到入口点呢?
从上图可以看出快慢指针在五号节点相遇。头结点距离2号节点(入口点)为1,5号节点距离2号节点的距离也为1。此时重新找一个节点从头结点开始遍历,另外一个节点从5号节点开始遍历,当两个节点相遇的时候就是入口节点。
为什么这样呢?应该是一个数学公式吧,这个我也没搞懂,但是测试的都通过
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if (pHead == null || pHead.next == null)
return null;
ListNode slow = pHead, fast = pHead;
do {
fast = fast.next.next;
slow = slow.next;
} while (slow != fast);//找到相遇点
if(slow==null)//如果相遇点为null,那么就意味着没有环
return null;
else{//相反,证明有环,那么从头节点
fast = pHead;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
三种有环的情况
-
第一种情况:交点在环开始之前
-
第二种情况:交点在环入口处
- 第三种情况:交点在环内
如何判断有环链表是否相交?
针对上面的前两种情况:
链表有环,我们可以根据链表有环而找出环的入口。也就是找到前两种情况的P点。然后根据无环链表的解法(查看文章目录)就可以找出交点。
针对上面的第三种情况:
我们可以分别找到链表一和链表二的环入口节点,各自的环入口节点即为各自第一次相交的节点。