判断链表是否有环并找出环的入口(Leetcode 142)

记录一下做题思路

# 题目描述

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
            

     

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值