剑指offer:Python 链表中环的入口点 图解

阅读目录

      • 题目描述
      • 思路和Python实现

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路和Python实现

思路:设置 快指针 和慢指针

  • 关于题目,首先我们要考虑的是,怎样判断链表成环?接着才是 怎么找出入口结点
  • 如何判断 单链表成环?设置的两枚指针是关键,假设快指针每次移动的步数是慢指针的两倍,让两枚指针同时从头出发,只要两者不相遇,就说明链表没有没有环,相遇就说明有环
    剑指offer:Python 链表中环的入口点 图解_第1张图片
  • 如何找到链表环的入口结点?要相遇肯定是在环中相遇!如下图:假设,快指针=2慢指针 ;入口结点 和 头结点 之间的距离为 a,入口结点 和 第一次相遇结点 之间的距离为b,链表环中剩下的长度为c,我来推导下两者之间的关系:↓↓↓
    2(a+b) =a+b+n(b+c) 变化一下-> a=(n-1)(b+c)+c 这个结论是什么意思? 如果让 慢指针 从头开始走,一定会在 快指针 走了整数圈后 在入口结点相遇,并不是 a 一定等于 c 要看快慢指针相差多少。
  • 当n=1 表示 快指针领先1圈,就相遇,那么第一次相遇在相遇点时,慢指针走的长度是a + b,快指针走的长度是a + b + c + b,因为假设的是:快指针每次走两步,因此 2(a + b)=(a + b + c + b),可以推出 a = c ,因此在快慢指针相遇的时候,令快指针再从头开始一步一步的走,慢指针继续走完c ,当两个指针再次相遇的节点就是入口节点。
    剑指offer:Python 链表中环的入口点 图解_第2张图片

Python 实现

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        if pHead is None:
            return None
        fast = pHead
        slow = pHead
        while fast and fast.next: # 判断链表是否成环,只要快指针和快指针下一步存在结点,就一直走
            fast = fast.next.next # 令快指针走两步
            slow = slow.next # 令慢指针走一步
            if fast is slow: # 如果两枚指针相遇,说明链表成环,退出循环
                break
        if fast is None or fast.next is None: # 出循环的第一种情况,两枚指针不相遇
            return None
        # 否则就是另一种情况break,即是两者相遇,链表成环
        fast = pHead # 令快指针 调到头部,每次走一步,慢指针接着在环里走
        while fast is not slow: # 如果两者没有相遇,就一直走
            fast = fast.next
            slow = slow.next
        return fast # 返回两者中其一都可以
        
if __name__ == '__main__': # 测试一下
    n1 = ListNode(1)
    n2 = ListNode(2)
    n3 = ListNode(3)
    n4 = ListNode(4)
    n5 = ListNode(5)
    n1.next = n2
    n2.next = n3
    n3.next = n4
    n4.next = n5
    n5.next = n2 # 这里新建一个链表为: 1 -> 2 -> 3 -> 4 -> 5 -> 2 环的入口为:2
    obj = Solution()
    print(obj.EntryNodeOfLoop(n1).val) # 最终输出结果也为:2

你可能感兴趣的:(数据结构与算法题目)