两个链表,可能相交,找出相交的节点,给出证明
1.若两个单链表一个为有环,一个无环. 那么肯定不能相交.
2.若二者都没有环, 问题就转化为 两个无环单链表是否相交,是否能找到第一个相交的节点,方法就是 快慢指针 。
3.若二者都有环,那么问题变成了两个有环单链表是否相交.
第一,先找到二者是否相交.
第二,若相交则需要遍历一遍找到相交点.
无环情况:
LeetCode 160. 相交链表
编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表:

在节点 c1 开始相交。
解析:
要想判断是否相交,肯定要看是否能找到相交的点,如果能让两个指针同时走到相交点,也就可以确定两个链表相交。因为相交后两个链表到终点的距离相等,那么只要两个指针能够消除两个链表之间的长度差就可以到达终点的距离相等。假设链表A比B长,pB到达结尾后指向headA,然后继续向前遍历,当pA到达结尾后指向headB,此时两者的长度差就消除了。继续遍历如果两者指向同一节点,返回节点,如果两者都走到结尾依然没有相交,就返回null。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
a = headA
b = headB
while a != b:
if not a:
a = headB
else:
a = a.next
if not b:
b = headA
else:
b = b.next
return a
LeetCode 142. 环形链表 II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
说明:不允许修改给定的链表。

快慢指针:设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点(结论1)。
接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口(结论2)。
证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。
证明结论2:
设:
链表头到环入口长度为–a
环入口到相遇点长度为–b
相遇点到环入口长度为–c

则:相遇时
快指针路程=a+(b+c)k+b ,k>=1 其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。
慢指针路程=a+b
快指针走的路程是慢指针的两倍,所以:(a+b)*2=a+(b+c)k+b
化简可得:
a=(k-1)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。
算法如下:
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
if not head:
return None
fast = head
slow = head
hasCycle = False
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
hasCycle = True
break
if not hasCycle:
return None
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
本文深入探讨了链表相交及环形链表的问题,包括两个链表相交的起始节点查找,以及环形链表中寻找入环首个节点的方法。通过快慢指针技巧,详细解析了如何判断并定位相交点和环入口,提供了LeetCode题目的解决方案。
557

被折叠的 条评论
为什么被折叠?



