Leecode---141、142环形链表

文章介绍了两种方法来检测和找到链表中的环。方法一是通过记忆化搜索,存储每个节点是否被访问过;方法二是使用快慢指针,快指针每次前进两步,慢指针前进一步,当它们相遇时即存在环。对于找到环的入口,快慢指针相遇后,再引入一个指针从头开始,直到与慢指针再次相遇,即可确定入环点。
摘要由CSDN通过智能技术生成

141 难度 : easy

在这里插入图片描述

个人主要思路是, 循环遍历每个节点, 判断该节点此前是否被访问过。
方法一: 时间8ms , 内存 6.8M ,

func hasCycle(head *ListNode) bool {
    var val = map[*ListNode]*ListNode{}
    if head == nil {
        return false
    }
    val[head] = head
      for head.Next != nil {
        if _, ok := val[head.Next]; ok {
            return true
        }else{
            val[head.Next] = head.Next
        }
        
        head = head.Next
    }
   return false
}

在这里插入图片描述

看了题解之后, 有提升空间
方法二: 快慢指针
使用两个指针, 进行遍历,
slow 每次步长1个节点, fast 每次步长2个节点

func hasCycle(head *ListNode) bool {
    slow, fast := head, head
    for fast != nil && fast.Next != nil {
        slow = slow.Next
        fast = fast.Next.Next
        if fast == slow {
            return true
        }
    }
    return false
}

在这里插入图片描述
使用快慢指针可以快执行时间和内存消耗都有很大提升

快慢指针参考: 添加链接描述

142: 难度 :medium

在这里插入图片描述

方法一: 用141 的方法一也是可以解决的, 于是做 了处理

func detectCycle(head *ListNode) *ListNode {
     var val = map[*ListNode]*ListNode{}
    if head == nil || head.Next == nil{
        return nil
    }
    val[head] = head
      for head.Next != nil {
        if _, ok := val[head.Next]; ok {
            return val[head.Next]
        }else{
            val[head.Next] = head.Next
        }
        
        head = head.Next
    }
   return nil
}

在这里插入图片描述
方法二: 题解里的快慢指针(这边直接参考官方的题解), 主要是推导出一个公式
在这里插入图片描述
主要根据图示, 设链表中环外部分的长度为 a。show 指针进入环后,又走了 b 的距离与 fast 相遇。此时,fast 指针已经走完了环的 n 圈,因此它走过的总距离为 a+n(b+c)+b=a+(n+1)b+nc.此时的slow 比fast 少走一圈

fast 走的路程:a+(n+1)b+nc
slow 走的路程:a+b

根据题意,任意时刻,fast 指针走过的距离都为show 指针的 2 倍。因此,我们有

a+(n+1)b+nc=2(a+b) ⟹ a=c+(n−1)(b+c)

我们会发现:从相遇点到入环点的距离加上 n-1 圈的环长,恰好等于从链表头部到入环点的距离。
所以在slow 与fast 相遇的时候, 再引入一个指针ptrptr 走距离a 时, slow 会走剩下的c+(n−1)(b+c), slow 先走c 走进入环点, 剩下的(n-1)圈的环长, 并到达入环点, 此时ptr 也在入环点, 然后就能锁定入环点了。

func detectCycle(head *ListNode) *ListNode {
    slow, fast := head, head
    for fast != nil {
        slow = slow.Next
        if fast.Next == nil {
            return nil
        }
        fast = fast.Next.Next
        if fast == slow {
            p := head
            for p != slow {
                p = p.Next
                slow = slow.Next
            }
            return p
        }
    }
    return nil
}

在这里插入图片描述
跟方法一比较, 消耗了时间, 但是内存消耗减少了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值