链表——4.环形链表II

力扣题目链接

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

说明:不允许修改给定的链表。

示例:

输入:head = [3,2,0,-4],pos = 1
输出:1
解释:链表中有环,其尾部连接到第二个节点

该题的意思首先是判断一个链表当中存不存在环(不存在的话返回null),其次输出该链表中存在的环的起点位置。

具体解题思路如《代码随想录》所示。我将用更加通俗易懂的讲法解释这个思路,思路是,利用快慢双指针法。

首先,定义一个快指针fast,一个慢指针slow,这两个指针都从头结点开始出发,唯一不同的点在于,fast指针每次前进两格,slow每次每次前进一格。在这种情况下,如果链表存在环的话,fast指针必然先进入环,slow指针后进入环。slow指针进入环时,fast可能还未走完一圈环,也有可能已经走了好几圈环。但在slow指针进入环后,由于slow每次前进一格,fast每次前进两格,所以slow指针和fast指针必然在环中相遇,因此fast指针和slow指针相遇了便证明了该链表存在环。

接着,需要找到链表中环的起点。

如图所示,我们可以假设快慢节点在红星处相遇,根据简单的数学知识,此时慢节点slow走了(x+y)个长度节点,而快节点fast走了x+y+n(y+z)个长度节点。由于快节点每次前进两格,慢节点每次前进一格,所以快节点前进的长度是慢节点的两倍,即x+y+n(y+z)=2*(x+y),化简移项后可以得到入口节点x=(n-1)*(y+z)+z,其中n代表fast在环中转的圈数。

求出x的关系式又代表什么呢?我们可以看见从头结点到入口节点之间的长度为x,x又等于(n-1)个环的长度再加上一个z的长度,这就可以理解为一个指针从头结点出发,一个指针从快慢指针相交处出发时,当两个指针相遇时,相遇的点就在入口节点处。这个关系式能记住就记住,记不住大不了画个图自己推导一下。

根据以上思路,我们可以去分析完整代码,完整代码如下:

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow = head
        fast = head
        
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            
            # If there is a cycle, the slow and fast pointers will eventually meet
            if slow == fast:
                # Move one of the pointers back to the start of the list
                slow = head
                while slow != fast:
                    slow = slow.next
                    fast = fast.next
                return slow
        # If there is no cycle, return None
        return None

理解思路后,代码分析起来就没有难度了,首先定义快慢节点,定义它们的移动方式,当快慢节点相遇时,将slow移到了头结点head,而fast节点依旧在相遇节点。接着重新设置两个节点的移动方式,都改为一格一格移动,只要slow和fast指针没有相遇,那便一直向后移动,直到两个指针相遇,即相遇在入口节点,return到slow,其实return到fast也可以。

  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值