【数据结构】研究链表带环问题

news2024/11/16 10:43:30

💯💯💯💯

本篇主要研究的是链表带环问题,快慢指针的应用,分析不同解法对带环链表的处理,梳理完本篇你将对链表的理解更加透彻

  • Ⅰ.研究链表带环问题
  • Ⅱ.扩展带环问题
    • 1.为什么慢指针和快指针一定会相遇?
    • 2.快指针一次走3步,4步…n步可以吗?
    • 3.慢指针走的距离和快指针走的距离?
  • Ⅲ.总结归纳
    • 结论:带环定理
  • Ⅳ.带环链表真题
      • 方法1:利用带环定理
      • 方法2:转换为相交链表问题

Ⅰ.研究链表带环问题

链表带环是什么意思呢?
就是一个链表有一个结点指向了前面结点导致又链接回来的问题
如果进行遍历就会变成死循环
在这里插入图片描述

那么如何判断一个链表是否带环呢?
链表带环问题Ⅰ
在这里插入图片描述

思路:
我们可以利用快慢指针,慢指针走一步,快指针走两步,当快指针进入环中时,慢指针肯定还在外面,当慢指针进环时,快指针可能已经走了好几圈,但一旦两个指针进环后,肯定会相遇,我们可以将带环问题,转换为相遇问题,也就是小学经常看到的,小明先跑50,速度为5m/s,小亮后跑速度为10m/s,问何时相遇。

我们只要判断它们是否相遇了,就能确定是否带环,因为如果没有带环的话,那就不可能相遇,快指针肯定先走出去。

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,
如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。
在这里插入图片描述

bool hasCycle(struct ListNode *head)
 {
    struct ListNode*fast,*slow;
    fast=slow=head;//快慢指针都从开头开始走
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)//如果慢指针等于快指针则一定在环里
        return true;
    }
    return false;//否则就不在环里
}

Ⅱ.扩展带环问题

1.为什么慢指针和快指针一定会相遇?

假设链表带环,快慢指针同时走,快指针先入环,慢指针后入环,当慢指针刚入环时,有可能与快指针相遇,也有可能与快指针相差很远,但这不是问题,关键的关键是它们两都在环里,并且快指针每次走两步,慢指针每次走1步,而它们每次走一步时,它们之间的距离就减少1,每走一步,快指针就追上一步,所以它们之间的距离在不断的缩小,最后肯定能追上。
在这里插入图片描述

并且不会出现套圈的现象,因为两个结点之间最小的距离也就是1了,每次缩小1,最后要么重合,要么还是重合,不可能从头上跳过去的。

还有慢指针在慢指针走到一圈之前,快指针肯定是可以追得上慢指针的,即相遇
慢指针刚入环时,与快指针最远距离可能为一个环距离吧,但想一想,当慢指针走了一环距离时,快指针走了多少?快指针走的是慢指针的2倍呀,那肯定是2圈了都,慢指针走1圈,快指针都要走两圈了,这里面肯定追上慢指针了。

2.快指针一次走3步,4步…n步可以吗?

其实这种本质上看的是相对位移量,只要我们算出相对位移量就可以判断了。上面快指针每次走2步慢指针每次走1步,它们每次走一步都会缩小1距离,而因为1就是最小距离单位,所以最后肯定会相遇。
但如果一次走三步,就不一定了
假设快慢指针都入环后,它们之间的距离为N
快指针每次走3步,慢指针每次走1步,那它们每次走,快指针都会缩小2个距离,那它们之间的距离就变成了N-2,再走就变成N-4,N-6……,这里就涉及N是奇数还是偶数了,当N是偶数时,那么最后它们是可以相遇的,如果是奇数,那这圈是不会相遇的,不过最后走完快慢指针之间的距离就变成-1了,也就是这个环的周长减1距离,这又要取决于环的周长是偶数还是奇数了……。
在这里插入图片描述

如果快指针每次走4步,道理也是一样的,在快慢指针都入环后,假设它们的距离为N
则每次距离都会缩小3,则最好是否相遇取决于N是否是3的倍数了。
在这里插入图片描述

3.慢指针走的距离和快指针走的距离?

在这里插入图片描述

你想一想快指针和慢指针在相遇前总共走了多远距离呢?
快慢指针是同时从开始位置走的,快指针走的快,先入环,慢指针走的慢,后入环。
前面我们知道fast在slow走满一圈之前追上,所以slow不可能走过一圈的,所以慢指针走的总距离为L+M

而快指针就不一定了,快指针走的快,先入环,谁知道它在环里走了多少圈了都,而且走的圈数越多说明这个环越小
在这里插入图片描述
所以快指针走的总距离为
L+M+nC (n至少为1)*
n为走过的圈数

Ⅲ.总结归纳

因为快慢指针之间存在着关系,所以我们可以列出一个表达式,也就是快指针走的距离是慢指针走的距离的2倍
2*(L+M)=L+M+n*C

所以L=n*C-M
当最好情况下n=1时,L=C-M
L是什么?L就是开始点到入口点的距离
C-M是什么?C-M就是相遇点到入口点的距离。

也就是:一个指针从链表的起始位置开始运行,一个指针从相遇点位置绕环,每次都走一步,两个指针最终会在入口点的位置相遇

在这里插入图片描述

结论:带环定理

让一个指针从链表的起始位置开始遍历,同时让一个指针从带环的相遇点位置开始遍历,两个指针都是每次走一步,最终一定会在入环处相遇!

Ⅳ.带环链表真题

给定一个链表,返回链表开始入环的第一个结点,如果链表无环,则返回NULL
在这里插入图片描述
《链表带环问题Ⅱ》
要求判断是否有环,如果有请返回入环的第一个结点。

方法1:利用带环定理

这就是我上面两个例子的结合,第一步判断是否有环,第二步利用上面的定理:在有环的链表中,从开始位置和相遇点同时出发,将会在入环点相遇。

struct ListNode *detectCycle(struct ListNode *head) 
{
    //首先判断是否有环
    struct ListNode *fast,*slow;
    fast=slow=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
        {
            //fast与slow现在就是相遇点
            //这时从开始点和相遇点同时走,当相等时,就是入环点
            while(head!=slow)//如果不相同就一直走
            {
                head=head->next;
                slow=slow->next;
            }
            return head;//当跳出来时就是入环点
        }
    }
    return NULL;
    
}

在这里插入图片描述

方法2:转换为相交链表问题

还有一种方法可以快速解决这个问题,我们可以将相遇点与后面那个结点断开
在这里插入图片描述
那从断开的结点开始是不是就相当于一个链表了,那这道题目就转变成了相交链表的问题了,求两个链表相交的结点问题,我在上一篇博客中有写过这种方法。
如果求两个相交链表的结点呢?
其实很简单:
第一步求出两个链表的长度
第二步让长度较长的链表先走长度差步
第三两个链表一起走,并进行比较,当两个链表的结点相同时就是相交结点。

在这里插入图片描述

struct ListNode *detectCycle(struct ListNode *head)
 {
  //首先要找到相遇点,才能断开它
  struct ListNode*fast,*slow;
  fast=slow=head;
  while(fast&&fast->next)
  {
      slow=slow->next;
      fast=fast->next->next;
      if(fast==slow)
      {
          //fast和slow现在就是相遇点,断开它和下一个结点并保存下一个结点的地址
          struct ListNode*newnode=slow->next;
          slow->next=NULL;
          //newnode就是新链表的头指针啦
    //开始求两个链表长度!
    int len1=0,len2=0;
    struct ListNode*tail1=head,*tail2=newnode;
    while(tail1)//计算链表1的长度
    {
        tail1=tail1->next;
        ++len1;
    }
    while(tail2)//计算链表2的长度
    {
        tail2=tail2->next;
        ++len2;
    }
    //两个链表长度是求出来来了,但不知道哪个是长链表哪个是短链表呀,所以还需要讨论下
    int gap=abs(len1-len2);
    struct ListNode*longlist=head,*shortlist=newnode;
    if(len1<len2)
    {
        longlist=newnode;
        shortlist=head;
    }
    //让长的链表先走长度差
    while(gap--)
    {
        longlist=longlist->next;
    }
    //然后两个链表再一起走,比较相同的时就是相交结点
    while(longlist!=shortlist)
    {
       longlist=longlist->next;
       shortlist=shortlist->next;
    }
    return longlist;//最后返回相交结点
      }
  }  
  return NULL;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/399341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

求职季必看系列:Java如何高效面试?

先看看这些java高频的面试重点吧 ​ 以下是初级程序员面试经常问到的问题&#xff1a; ■ Spring的三大特性是什么&#xff1f; ■ Spring IOC和AOP 你是如何理解并且使用的&#xff1f; ■ 说一下ElasticSearch为什么查询的快&#xff1f;是如何存储的&#xff1f;在项目中…

JUC并发编程设计模式

一、保护性暂停 1.1 定义 即Guarded Suspension,用在一个线程等待另一 个线程的执行结果 要点 ● 有一个结果需要从一个线程传递到另一 个线程&#xff0c;让他们关联同一一个GuardedObject ● 如果有结果不断从一个线程到另一个线程那么可以使用消息队列&#xff08;生产者…

SpringBoot 集成 elasticsearch 7.x和对应版本不一致异常信息处理

开源框架springboot框架中集成es。使用org.springframework.data.elasticsearch下的依赖,实现对elasticsearch的CURD,非常方便&#xff0c;但是springboot和elasticsearch版本对应很严格&#xff0c;对应版本不统一启动会报错。 文章目录开源框架Elasticsearch 7.x安装Elastics…

Visual Studio 2019 + Qt 项目版本信息新增到资源以及通过代码读取资源存储的版本信息

文章目录前言一、如何在VisualStudio2019中新增项目版本信息二、在程序中调用项目版本信息1.引入库version.lib1.1.通过vs自带的属性页引入库1.2.手动引入库2.新增版本信息读取类3.调用类获取信息总结前言 本文主要讲述如何在Visual Studio 2019 以及Qt结合的开发项目中&#…

WPF 自定义DataGrid控件样式模板5个

WPF 自定义DataGrid控件样式样式一&#xff1a;样式代码&#xff1a;<!--DataGrid样式--><Style TargetType"DataGrid"><!--网格线颜色--><Setter Property"CanUserResizeColumns" Value"false"/><Setter Property&q…

React解决样式冲突问题的方法

React解决样式冲突问题的方法 前言&#xff1a; 1、React最终编译打包后都在一个html页面中&#xff0c;如果在两个组件中取一样类名分别引用在自身&#xff0c;那么后者会覆盖前者。 2、默认情况下&#xff0c;只要导入了组件&#xff0c;不管组件有没有显示在页面中&#x…

Fikker安装SSL证书

Fikker 基于nginx&#xff0c; 订单详细中下载nginx格式&#xff0c; 解压后包含 yourdomain.com.crt 和 yourdomain.com.key 2个文件&#xff0c;将内容粘贴到输入框中.1、说明&#xff1a;在【主机管理】中设置网站域名对应的SSL 数字证书&#xff08;CRT/CER&#xff09;和证…

[数据结构与算法(严蔚敏 C语言第二版)]第1章 绪论(课后习题+答案解析)

1. 简述下列概念:数据、数据元素、数据项、数据对象、数据结构、逻辑结构、存储结构、抽象数据类型。 数据 数据是客观事物的符号表示&#xff0c;是所有能输人到计算机中并被计算机程序处理的符号的总称。数据是信息的载体&#xff0c;能够被计算机识别、存储和加工 数据元素…

Imx6ull交叉编译nginx

Imx6ull交叉编译nginx 需要下好的包 Nginx(下载压缩包源码) nginx-rtmp-module(可以下载压缩包源码也可以 git clone https://github.com/arut/nginx-rtmp-module.git) pcre&#xff08;下载源码&#xff09; zlib&#xff08;下载源码&#xff09; openssl&#xff08;下载源…

国外SEO升级攻略:如何应对搜索引擎算法变化?

搜索引擎优化&#xff08;SEO&#xff09;是一个动态的领域&#xff0c;搜索引擎的算法经常会发生变化&#xff0c;这意味着SEO专业人员需要保持更新的技术知识和策略&#xff0c; 以适应变化并提高网站的排名。 以下是一些应对搜索引擎算法变化的升级攻略&#xff1a; 创造…

Linux-0.11 kernel目录进程管理sched.c详解

Linux-0.11 kernel目录进程管理sched.c详解 sched.c主要功能是负责进程的调度&#xff0c;其最核心的函数就是schedule。除schedule以外&#xff0c; sleep_on和wake_up也是相对重要的函数。 schedule void schedule(void)schedule函数的基本功能可以分为两大块&#xff0c;…

数据结构-带头双向循环链表

前言&#xff1a; 链表有很多种&#xff0c;上一章结&#xff0c;我复盘了单链表&#xff0c;这一章节&#xff0c;主要针对双链表的知识点进行&#xff0c;整理复盘&#xff0c;如果将链表分类的话&#xff0c;有很多种&#xff0c;我就学习的方向考察的重点&#xff0c;主要…

一点就分享系列(实践篇6——上篇)【迟到补发】Yolo-High_level系列算法开源项目融入V8 旨在研究和兼容使用【持续更新】

一点就分享系列&#xff08;实践篇5-补更篇&#xff09;[迟到补发]—Yolo系列算法开源项目融入V8旨在研究和兼容使用[持续更新] 题外话 去年我一直复读机式强调High-level在工业界已经饱和的情况&#xff0c;目的是呼吁更多人看准自己&#xff0c;不管是数字孪生交叉领域&#…

React全家桶(一)

课程内容 1、React基础 2、React Hooks 3、React路由 4、React Redux 5、组件库 6、Immutable 7、Mobx 8、ReactTS 9、单元测试 10、dvaumi 一、React介绍 1、React起源与发展 2、React与传统MVC的关系 3、React的特性 4、虚拟DOM 二、create-react-app 1、全局安装…

数学小课堂:数学难题的意义(善用工具和跳出圈外)

文章目录 引言I 几何学中的古典难题(几何作图题)1.1 伽罗瓦1.2 伽罗瓦理论II 数学难题的启发2.1 跳出圈外2.2 工具的作用引言 毕达哥拉斯定理做保障:任何自然数的平方根都可以用圆规和直尺作出来 高斯用直尺和圆规作图解决正十七边形画法的问题,正十七边形的边长计算出来…

如何利用海外主机服务提高网站速度?

网站速度是任何在线业务成功的关键。快速的网站速度可以让用户更快地访问您的网站&#xff0c;增加页面浏览量。对于拥有全球用户的网站而言&#xff0c;选择一个海外主机服务商是提高网站速度的有效方法之一。下面是一些利用海外主机服务(如美国主机、香港主机)提高网站速度的…

Job System

01-C&#xff03;Job System概述官方文档 Unity C&#xff03; Job System允许用户编写与Unity其余部分良好交互的多线程代码&#xff0c;并使编写正确的代码变得更加容易。编写多线程代码可以提供高性能的好处。其中包括显着提高帧速率和延长移动设备的电池寿命。C&#xff03…

iOS开发-bugly符号表自动上传发布自动化shell

这里介绍的是通过build得到的app文件和dSYM文件来打包分发和符号表上传。 通过Archive方式打包和获得符号表的方式以后再说。 一&#xff1a;bugly工具jar包准备 bugly符号表工具下载地址&#xff1a;(下载完成后放入项目目录下&#xff0c;如不想加入git可通过gitIgnore忽略…

doPost的实际使用

目录 前言 一、doPost是什么&#xff1f; 二、使用步骤 1.doPost的请求方法 2.需要引入依赖 总结 前言 本章主要记录一下doPost的请求公用方法的使用。 一、doPost是什么&#xff1f; 它其实就是一个http的post请求方式。 二、使用步骤 1.doPost的请求方法 当我们系…

使用Endnote自定义参考文献格式

使用Endnote自定义参考文献格式 使用Endnote插入参考文献&#xff0c;若要设置期刊指定格式或自己想要的参考格式&#xff0c;使用EndNote自定义方法&#xff0c;步骤如下。 注&#xff1a;有的期刊会给出EndNote的格式文件&#xff0c;那样直接导入就行。 文章目录使用Endnot…