本文参考

出自LeetCode上的题库 —— 环形链表II,哈希表和快慢指针两种解法都需要O(n)的时间,但快慢指针仅占用O(1)的空间

https://leetcode-cn.com/problems/linked-list-cycle-ii/

环形链表问题

给定一个链表的头节点 head,返回链表开始入环的第一个节点(不允许修改链表)
如果链表无环,则返回null。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环

示例1:
输入:head = [3,2,0,-4]
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点

示例2:
输入:head = [1,2]
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点

示例3:
输入:head = [1]
输出:返回 null
解释:链表中没有环

解题思路

首先是特殊情况,当没有节点,或有节点却不存在环的情况下,容易通过节点或节点的next指针是否空进行判断

当节点间存在环路时,第一种直观的解法,使用一个指针沿着链路走下去,每走一步将节点存入set集合,当碰到重复出现的节点时,该节点就是环路的入口;

第二种解法需要应用两遍双指针,可能刚接触这道题时已经想到了快慢指针,但是我们无法保证快指针和慢指针相遇的位置一定是环路的入口,以至于否定了这种解法。此处需要一定的数学分析,在快慢指针相遇的位置引入第三个指针:

令总节点数为$n$,头节点为$head$,环路的入口节点为$entry$,环路中快慢指针相遇的节点位置为$meet$,定义距离$a=Distance(head,entry)$,距离$b=Distance(entry,meet)$,距离$c=Distance(meet,entry)$,满足$n=a+b+c$

当快慢指针相遇时,快指针走过的路径长度为$d_{fast}=a+n(b+c)+b$,慢指针走过的路径长度为$d_{slow}=a+b$,我们预先设置快指针每次走两步,慢指针每次走一步,则$d_{fast}=2d_{slow}=a+n(b+c)=2(a+b)$,化简得$a=c+(n-1)(b+c)$,$a$的长度是$c$的长度加上$(n-1)$圈的环路长度

因此,我们引入第三个指针ptr,慢指针从相遇位置开始移动,ptr从头指针开始移动,由公式$a=c+(n-1)(b+c)$可知,二者相遇的位置即为环路的路口

哈希表解法

class ListNode:

  def __init__(self, x):

    self.val = x

    self.next = None

class
Solution:

  def detect_cycle_1(self, head: ListNode) -> ListNode:

    if head is None or head.next is None:

      return None

    node_set = set()

    curr_node = head

    while curr_node not in node_set:

      node_set.add(curr_node)

      if curr_node.next is None:

        return None
      else
:

        curr_node = curr_node.next

    return curr_node

快慢指针解法

def detect_cycle_2(self, head: ListNode) -> ListNode:

  slow = fast = head

  while fast is not None:

    # 慢指针每次走一步 

    slow = slow.next

    if fast.next is None:

      return None

    # 快指针每次走两步 


    fast = fast.next.next

    # 快慢指针相遇 

  if fast == slow:

    ptr = head

    # 建立新的双指针走法 

    while ptr != slow:

      ptr = ptr.next
      slow = slow.next

      return ptr

    return None

打败算法 —— 环形链表 II的更多相关文章

  1. 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II

    [算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...

  2. LeetCode142 环形链表 II

    给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? //章节 - 链表 //二.双指针技巧 //2.环 ...

  3. Leetcode 142.环形链表II

    环形链表II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 说明:不允许修改给定的链表. 进阶:你是否可以不用额外空间解决此题? 链表头是X,环的第一个节点是Y,sl ...

  4. Leetcode.142-Linked-list-cycle-ii(环形链表II)

    环形链表II 思路 https://www.cnblogs.com/springfor/p/3862125.html https://blog.csdn.net/u010292561/article/ ...

  5. LeetCode 142. 环形链表 II(Linked List Cycle II)

    142. 环形链表 II 142. Linked List Cycle II 题目描述 给定一个链表,返回链表开始入环的第一个节点.如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整 ...

  6. Java实现 LeetCode 142 环形链表 II(二)

    142. 环形链表 II 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始 ...

  7. 【LeetCode】142. 环形链表 II

    142. 环形链表 II 知识点:链表:set:快慢指针 题目描述 给定一个链表,判断链表中是否有环. 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表 ...

  8. 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II

    今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...

  9. LeetCode 142:环形链表 II Linked List Cycle II

    给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...

随机推荐

  1. 【C# 线程】线程局部存储(TLS) 实战部分 ThreadStatic|LocalDataStoreSlot|ThreadLocal<T>

    往袋子里面装苹果 错误案例示范 关于C#多线程的文章,大部分都在讨论线程的起停或者是多线程同步问题.多线程同步就是在不同线程中访问同一个变量(一般是线程工作函数外部的变量),众所周知在不使用线程同步的 ...

  2. 【C#反射】动态创建类型实例

    转载自:https://www.cnblogs.com/dytes/archive/2012/06/29/2569488.html .NET中除了构造函数外,还有多种方式可以创建类型的实例.下面总结了 ...

  3. 白话OAuth2.0

     一.OAuth是什么 OAuth简写:Open Authorization(开放授权).百度百科上是这么说的:为用户资源提供了一个安全,开放而又简易的标准.解决了密码的反模式问题(第三方应用不需要知 ...

  4. 5.注入内部Bean

    我们将定义在 <bean> 元素的 <property> 或 <constructor-arg> 元素内部的 Bean,称为"内部 Bean". ...

  5. Python 并发编程(下)

    Python 并发编程(下) 课程目标:掌握多进程开发的相关知识点并初步认识协程. 今日概要: 多进程开发 进程之间数据共享 进程锁 进程池 协程 1. 多进程开发 进程是计算机中资源分配的最小单元: ...

  6. C#10新特性-lambda 表达式和方法组的改进

    C# 10 中对Lambda的语法和类型进行了多项改进: 1. Lambda自然类型 Lambda 表达式现在有时具有"自然"类型. 这意味着编译器通常可以推断出 lambda 表 ...

  7. DDos攻击竟然这么恐怖,它的原理是什么?

    DDOS的定义 分布式拒绝服务(DDoS:Distributed Denial of Service)攻击指借助于客户/服务器技术,将多个计算机联合起来作为攻击平台,对一个或多个目标发动DDoS攻击, ...

  8. Python 从底层结构聊 Beautiful Soup 4(内置豆瓣最新电影排行榜爬取案例)

    1. 前言 什么是 Beautiful Soup 4 ? Beautiful Soup 4(简称 BS4,后面的 4 表示最新版本)是一个 Python 第三方库,具有解析 HTML 页面的功能,爬虫 ...

  9. OpenCascade极简环境搭建(QT环境)

    现在网上关于OpenCascade(OCCT)的环境搭建几乎都是下载源码,然后实时MinGW来编译生成源码.但是,官方有提供Windows平台下的可执行文件,如果想快速了解OpenCascade(OC ...

  10. 一些Docker 操作集合

    基本 显示所有容器(包括已停止): docker container ls -a 删除所有容器: docker stop $(docker ps -q) docker rm $(docker ps - ...