在线OJ——链表经典例题详解

引言:本篇博客详细讲解了关于链表的三个经典例题,分别是:环形链表(简单),环形链表Ⅱ(中等),随机链表的复制(中等)。当你能毫无压力地听懂和成功地写出代码时,那就一定可以充分的证明你的链表知识学习地非常扎实了!

更多有关C语言的知识详解可前往个人主页:计信猫

目录

一,环形链表(简单)

1,题目描述

2,思路分析

3,代码解答

 二,环形链表(简单)的拓展

1,提出问题

2,问题Ⅰ的解答

3,问题Ⅱ的解答

4,问题Ⅱ中C与N的关系

三,环形链表 Ⅱ(中等)

1,题目描述

2,思路分析

3,代码解答

四,随机链表的复制(中等)

1,题目描述

2,思路分析

3,代码解答

五,结语


一,环形链表(简单)

1,题目描述

OJ链接:环形链表

       给你一个链表,判断链表中是否存在环,若存在,则返回true,反之,则返回false

2,思路分析

        为了解出这道题,我们可以使用一个在链表中可谓是大名鼎鼎的方法——快慢指针

        所谓的快慢指针就是定义两个结构体指针slow和fast,而fast指针每次比slow指针多走一步。假如我们将fast比作兔子slow比作乌龟

        那么显而易见,假如整个链表里边没有环,则兔子(fast指针)一定会先走到NULL;假如整个链表里边有环,则兔子(fast指针)一定会先进入环,并一直在环里边循环着走,一直到乌龟(slow指针)进入环,由于兔子乌龟具有速度差,所以在某一时间刻乌龟兔子一定会相遇,所以如果兔子乌龟相遇了,即链表有环。

3,代码解答

if(head==NULL)//判断链表是否为空{return false;}struct ListNode*fast=head->next;//定义快指针struct ListNode*slow=head;//定义慢指针while(fast&&fast->next){if(fast==slow)//两指针相遇,则成环{return true;}fast=fast->next->next;//快指针每次走两步slow=slow->next;//慢指针每次走一步}return false;

 二,环形链表(简单)的拓展

1,提出问题

假如你正在参加某个hr的面试,而面试官刚刚好问到你这个问题,经过充分准备的你毫不费力地将这道题秒杀了。但面试官接下来又提出了两个问题:

1,为什么fast和slow指针一定会相遇,请给出证明

2,当fast指针一次走n步时,快慢指针还会不会相遇?

这时候,阁下又该如何是好呢?

2,问题Ⅰ的解答

        其实遇到这种问题我们完全没必要慌张,我们只需要拿出作为程序员严谨的态度给予证明就可以了。

        我们可以假设在fastslow都进入环的时候,两指针的间距为N。既然每进行一次追击,fast都前进两步,slow前进一步,那么它们之间的距离一定会缩小一步

那么当我们进行了N次追击,则间距则会如此变化:N,N-1,N-2……1,0

        所以如此来看,两指针的间距一定会变为0,那么fast和slow指针也一定会相遇!(第一关通过,获得50%的offer)

3,问题Ⅱ的解答

        此时对于n的具体取值我们就需要分开讨论了,我们就先以n等于3来进行讨论吧!

我们设进入环的时候两指针的间距d等于N,故每一次追击之后d=N-(n-1)=N-2,再设整个环的长度为C

   

         当d偶数时,距离每次减少2,则可以追上。

        但当d为奇数时,就要另当别论了:

d为奇数时,第一次的追击则会错过:N,N-2,N-4……1,-1。而这里的-1意味着fast指针会跑到slow指针的前一位去,并开始新一轮的追击。

        那么此时我们就需要再次讨论d=C-1的奇偶关系了。

C奇数时,d=C-1偶数,则可以追上。
C偶数时,d=C-1奇数,则又会进入下一次追击,进入死循环,永远也追不上

         所以其他n的取值情况也就同样方法继续思考了。(第二关通过,获得100%的offer)

4,问题Ⅱ中C与N的关系

        看了上面问题Ⅱ的解析后,我们都知道了快慢指针是否可以相遇与CN的奇偶性相关。而CN之间是否有存在着奇偶性的关系呢?答案是肯定的。

我们还是以n=3来进行分析,假设进环之前的路程长度为L,当slow进入环的时候,fast已经在环里边走了x圈。

而此时slow和fast指针走的路程分别如下:

        因为n=3,那么此时fast走的路程就是slow走的路程的三倍,所以我们可以得到等式:

3*L=L+x*C+C-N

        那么进行等式化简之后,我们便可以得到:

2*L=(x+1)*C-N

        所以在问题Ⅱ中,若d=N奇数C偶数的条件一定是不存在的!!原因如下:

三,环形链表 Ⅱ(中等)

1,题目描述

OJ链接:环形链表Ⅱ

        这次的不一样的地方就是需要在普通环形链表的基础上返回链表成环的节点。

2,思路分析

        关于这道题,我将会介绍一个十分巧妙的方法:一个指针从链表的头节点head开始出发,另一个指针从fast和slow指针相遇的节点meet出发,最终它们一定会在成环的起始节点相遇

证明:

还是老样子,我们假设在fastslow相遇的时候,fast已经走了x圈。

那么此时slowfast走的路程分别为:

        所以我们便可以得到如下等式:

2(L+N)=L+x*C+N     =>    L=x*C-N

         故等号左边的L就表示第一个指针从头节点head成环起始节点的距离,等号右边的x*C不就相当于是周期吗,并没有影响,剩下的N不就表示着meet节点成环起始节点的距离吗?所以等号左右两边相等,以上方法成立!

3,代码解答

struct ListNode *detectCycle(struct ListNode *head) 
{struct ListNode*fast=head;struct ListNode*slow=head;//寻找meet节点while(fast&&fast->next)    {slow=slow->next;fast=fast->next->next;if(slow==fast){struct ListNode*meet=slow;//找到meet节点struct ListNode*cur=head;//使用cur从头节点出发while(meet!=cur){cur=cur->next;meet=meet->next;}return meet;//cur和meet相遇的节点则为成环起始节点}}return NULL;
}

四,随机链表的复制(中等)

1,题目描述

OJ链接:随机链表的复制

        给定你一个链表,链表中含有一个随即指针random,它指向链表的其他节点或者NULL,如下:

         而你需要做的就是复制一个与原链表一模一样的链表,并且与对原链表毫无影响

2,思路分析

        其实这道题本身不难,复制一个链表简直易如反掌,而唯一的难点就是这个结构体成员random指针。它导致了复制random时,可能链表的那个random节点还没出现的问题。

         但是我们可以以以下方式解决问题:

        如上所示,我们可以先在每一个原链表节点之后插入一个与原节点一模一样的节点(先不管random指针),然后我们再对插入节点的random指针赋值,最后再将插入的指针取下来就可以了

        可能很多人会问道,random指针如何赋值呢?其实很简单,当我们将节点插入之后,random指针的值不就是原指针random所指向的值的next吗?这样,random的赋值就完美的解决了! 

3,代码解答

struct Node* BuyNode(int val)//设计一个创建节点的函数
{struct Node*newnode=(struct Node*)malloc(sizeof(struct Node));newnode->next=NULL;newnode->val=val;return newnode;
}
struct Node* copyRandomList(struct Node* head)
{
//防止空链表if(head==NULL){return NULL;}//创建后继节点struct Node*cur=head;while(cur){struct Node*newnode=BuyNode(cur->val);newnode->next=cur->next;cur->next=newnode;cur=cur->next->next;}//赋值randomstruct Node*newcur=head;struct Node*follow=newcur->next;while(follow){if(newcur->random==NULL)//random指向NULL就特殊处理赋值NULL{follow->random=NULL;//指针遍历链表的移动newcur=newcur->next->next;if(follow->next){follow=follow->next->next;}else{break;}}else{follow->random=newcur->random->next;//指针遍历链表的移动newcur=newcur->next->next;if(follow->next){follow=follow->next->next;}else{break;}}}//将后继结点分离struct Node*phead=head->next;struct Node*ptail=head->next;while(ptail->next){ptail->next=ptail->next->next;ptail=ptail->next;}return phead;
}

五,结语

        其实这些题讲起来看起来非常轻松,但也耗费了我不少时间去做出它(甚至还是在看了题解的前提下)。

        但让我值得欣慰的是,我还是结合题解做出了这些题,甚至第二题我还自己想出来自己的方法,而且我也十分顺利的在博客里清楚的讲解出了每道题的做法。这也证明了我的链表学习还是取得了效果。

        希望我的这篇博客也可以同样帮助到热爱编程学习的你,让我们一起进步一起加油!!

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

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

相关文章

再学Java基础——final关键字

在Java中,final关键字是一个修饰符,它可以应用于类、方法、变量和常量。以下是final关键字在Java中的不同用途及其作用: final类: 当一个类被声明为final时,它不能被继承。这意味着没有其他类可以扩展这个类。作用&…

【莫比乌斯变换-02】关于莫比乌斯变换属性梳理

文章目录 一、说明二、多视角看莫比乌斯变换2.1 从几何角度2.2 复分析中的莫比乌斯变换2.3 莫比乌斯变换运算组合2.4 莫比乌斯变换的不动点2.5 三个点决定一个莫比乌斯变换2.6 交叉比2.7 莫比乌斯变换的逆变换 三 莫比乌斯变换性质证明3.1 证明1:莫比乌斯变换将圆变…

【莫比乌斯变换-03】python实现圆对圆的变换

文章目录 一、说明二、python实现复平面的莫比乌斯变换三、线的变换四、画笑脸 一、说明 我们在前面的文章中,叙述了莫比乌斯变换的复数分析,以及种种几何属性,本篇中叙述如何程序地实现:复平面上的圆在莫比乌斯变换下的图像是另…

基于高德 API 的自动获取气候数据的 Python 脚本

文章目录 高德申请 Key脚本介绍运行结果示例 源代码: https://github.com/ma0513207162/PyPrecip。pyprecip\reading\read_api.py 路径下。 项目介绍:PyPrecip 是一个专注于气候数据处理的 Python 库,旨在为用户提供方便、高效的气候数据处理…

linux基本操作

vim的基本操作 正常模式:启动vim后默认处于正常模式。不论位于什么模式,按下Esc建都会进入正常模式。 插入模式:在正常模式中按下i,l,a,A等键,会进入插入模式。现在只用记住按i键会进行插入模…

文本内容如何扫码展示?文本转二维码常用技巧

随着网络的不断发展,现在很多人会通过二维码的方式来作为内容的载体,用来给其他人提供需要的信息或者其他内容。其中,将文本制作二维码就是很常用的一种方式,通过扫码展示文字内容,比如信件、物品信息、联系方式等类型…

python学习笔记----函数进阶(七)

一、函数多个返回值 def test_return():x 1y "hello"z Truereturn x, y, za, b, c test_return()print(a) print(b) print(c)二、函数多种传参方式 2.1 函数参数种类 根据使用方式上的不同,函数有4种常见参数的使用方式: 位置参数关键…

EPAI手绘建模APP资源管理和模型编辑器2

g) 矩形 图 26模型编辑器-矩形 i. 修改矩形的中心位置。 ii. 修改矩形的长度和宽度。 h) 正多边形 图 27模型编辑器-内接正多边形 图 28模型编辑器-外切正多边形 i. 修改正多边形的中心位置。 ii. 修改正多边形中心距离端点的长度。 iii. 修改正多边形的阶数。阶数为3&…

Linux Multipath极简安装配置

1.安装软件 #yum install -y device-mapper* 2.开启并设置开机启动 #systemctl start multipathd && systemctl enable multipathd 3.连接存储 在存储上对主机进行卷映射 4.修改配置文件 注:此配置文件可能存在,也可能不存在&#xff0c…

禅道项目管理系统身份认证绕过漏洞复现(QVD-2024-15263)

0x01 产品简介 禅道项目管理软件是国产的开源项目管理软件,专注研发项目管理,内置需求管理、任务管理、bug管理、缺陷管理、用例管理、计划发布等功能,完整覆盖了研发项目管理的核心流程。 0x02 漏洞概述 2024年4月,互联网披露禅道系统存在身份认证绕过的漏洞情报。经分…

【Unity 协程】

Unity中的协程(Coroutine)是一种编程结构,它允许你以一种看似同步的方式编写可能需要异步执行的代码。协程特别适用于需要在一定时间后执行操作,或者在循环执行某段代码直到某个条件满足时的场景。 协程使用IEnumerator委托来实现…

Qt中的对象树

一. QT对象树的概念 QObject 的构造函数中会传入一个 Parent 父对象指针,children() 函数返回 QObjectList。即每一个 QObject 对象有且仅有一个父对象,但可以有很多个子对象。 那么Qt这样设计的好处是什么呢?很简单,就是为了方…

基于HAL库的stm32中定时器的使用--定时器中断每隔一秒进行led灯的闪烁以及定时器生成PWM

一:什么是定时器 (1)stm32定时器,是存在于stm32单片机中的一个外设。stm32共有八个定时器,两个高级定时器(TIM1、TIM8),四个通用定时器(TIM2、TIM3、TIM4、TIM5&#xff…

docker 指定根目录 迁移根目录

docker 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、启动docker程序前就手动指定docker根目录为一个大的分区(支持动态扩容),事前就根本上解决根目录空间不够问题3.1.0、方法思路3.1.1、docker官网安装文档3.1.2、下载docker安装包3.1.3、安装doc…

贪吃蛇(下)游戏的实现

感谢大佬的光临各位,希望和大家一起进步,望得到你的三连,互三支持,一起进步 个人主页:LaNzikinh-CSDN博客 文章目录 前言一.蛇和食物的打印二.游戏的运行逻辑三.结束游戏 (善后工作)四.游戏的测…

找出两个数的最小公倍数和最大公约数

1 问题 已知两个数,用代码写出程序,求两个数的最小公倍数和最大公约数? 2 方法 利用Python自定义函数解决 代码清单 1 #Made by Txd,Hsy,Lyhdef calculation(x,y):#自定义一个函数 common_multiplemin(x,y)#找出两个数最小的那个数 for i in rang…

【数据结构和算法】--RangeSet时间范围管理示例

目录 一、问题二、RangeSet实现原理2.1、RangeSet常用方法2.2、核心原理2.3、核心特性2.4、基本使用 三、具体应用 一、问题 最近项目要求对一批时间范围进行管理,要求不能交叉。RangeSet是专门用于高效处理范围集合。 二、RangeSet实现原理 RangeSet表示一组不重…

C语言中字符串输入的3种方式

Ⅰ gets() 函数 gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间 # include <stdio.h> int main(void) {char a[256] {0};gets(a);printf("%s",a);return 0; }Ⅱ getchar() # include <stdio.h> int mai…

工业光源环形系列一AOI光源特点

产品特点 ◆具有环形光源所有的特点&#xff1b; ◆采用不同角度多色光&#xff0c;使被照物体的成像更具立体特征&#xff1b; ◆每种颜色可独立控制。

MySQL为什么默认引擎是InnoDB?

因为InnoDB特别强大,其支持很多东西 1.支持事务: 意味着对于一个复杂的SQL语句要么全部执行成功,要么全部失败,因为其底层是原子性的 2.支持并发(行级并发) 意味着面对高并发,多个用户可以同时访问一个表的不同行,不同行之间上锁,而不是给一个表上锁,这样就提高了高并发的性能和…