链表之链表含环,相交等问题

本文深入探讨了链表相交及环形链表的问题,包括两个链表相交的起始节点查找,以及环形链表中寻找入环首个节点的方法。通过快慢指针技巧,详细解析了如何判断并定位相交点和环入口,提供了LeetCode题目的解决方案。

两个链表,可能相交,找出相交的节点,给出证明
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值