记录一下做题思路
# 题目描述
Given a linked list, return the node where the cycle begins. If there is no cycle, return null
.
To represent a cycle in the given linked list, we use an integer pos
which represents the position (0-indexed) in the linked list where tail connects to. If pos
is -1
, then there is no cycle in the linked list.
Note: Do not modify the linked list.
# 解题思路
- 题目可以分解为两个任务,首先解决链表有环问题,然后寻找环的入口。
- 如果采用暴力记录的方式,两个子问题变成一个问题,不讨论。
- 首先判断链表是否有环。很早以前看过这个问题,用快慢两个指针同时遍历,如果没有环,则慢指针永远追不上快指针;如果有环,快指针和慢指针会在环中相遇。直接贴代码:
class Solution(object): def hasCycle(self, head): """ :type head: ListNode :rtype: bool """ pslow = head if head: pfast = head.next else: return False while pfast and pslow: if pfast == pslow: return True pslow = pslow.next if pfast.next: pfast = pfast.next.next else: pfast = pfast.next return False
接下来的问题是如何找到环的入口。分析一下当前的已知条件:1、链表入口;2、链表有环;3、快慢指针相遇节点。
- 能否仅从快慢指针相遇节点出发,再次走到链表入口。不能,在环内无论怎么走,所有节点从位置上看都是等价的,所以仅从相遇节点出发无论如何是找不到入口的。
- 要想找到入口,只能从链表入口开始探索。同理仅从链表入口出发也是无法确定环的入口的。
- 因此只有从链表入口和相遇节点同时开始探索,才有可能找到环的入口。为了不跳过环的入口,链表入口指针只能一步一步向前走,同理相遇节点指针也只能一步一步向前走,否则总有一种情况会跳过环的入口。
- 接下来的是手工测试出来的发现:P1从链表入口出发,每次走一步;P2从相遇节点的下一节点出发,每次走一步;P1和P2会在环的入口处相遇。虽然是手工测试出来的发现,但是这里一定是可以证明出来的,等有空了尝试证明一下。代码如下:
class Solution(object): def detectCycle(self, head): """ :type head: ListNode :rtype: ListNode """ pslow = head if head: pfast = head.next else: return None while pfast and pslow: if pfast == pslow: break pslow = pslow.next if pfast.next: pfast = pfast.next.next else: pfast = pfast.next if pfast != pslow: return None else: pslow = pslow.next pfast = head while pslow and pfast: if pslow == pfast: return pslow else: pslow = pslow.next pfast = pfast.next