《剑指offer》【链表中环的入口结点】(python版)

题目描述:一个链表中包含环,请找出该链表的环的入口结点。

思路:本题也是一个使用快慢双指针解决的经典问题。受之前的题目【求倒数第k个结点】的启发,我们假设原题中链表尾结点的next不是为空,而是指向我们找到的倒数第k个结点,形成一个有k个结点的环,那么这个结点其实也就是本题中要求的环的入口结点。也就是说只要我们知道本题中环中结点个数,就可以沿用上一题的做法解决问题。

假设有p,q两指针,p每步跨一个结点,q每步跨两个结点。那么经过k步之后q比p多走过的结点数为k。如果链表中没有环,那么q永远在p的前面,两指针不会相遇。如果链表有环,且环中结点个数为r,那么q会进入环内绕圈。如果两指针会在相遇,一定是在环内,并且q比p多绕n圈;也就是说一定存在k,只要满足k=n * r,就能使两指针相遇。

如下图所示,假设链表起点为a,入口结点为b,相遇点为c,ab段长度为m,bc段长度为n,环长度为r。经过上面的证明,我们知道c点一定存在,并且根据两指针走过的路程,存在等式2(m+n+h*r)= m+n+g*r,这样我们得到m=(g-2h)*r-n,也就是说ac段长度是环长度的整数倍。如果p指针重新从链表头出发,q指针从相遇点c出发,步伐一致,那么当p走到b点,q也正好走到b。

示意图

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if not pHead or not pHead.next or not pHead.next.next:
            return None
        slow = pHead.next
        fast = slow.next
        # 找到相遇点
        while fast != slow and fast.next:
            slow = slow.next
            fast = fast.next.next
        if slow == fast:
            # 慢指针回到表头,快指针留在相遇点,二者同步往前直到相遇在入口结点
            slow = pHead
            while slow != fast:
                fast = fast.next
                slow = slow.next
            return slow
        return None

猜你喜欢

转载自blog.csdn.net/qq_20141867/article/details/80931915