在线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;
   }
   //赋值random
   struct 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;
}

五,结语

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单调栈|496.下一个更大元素I

力扣题目链接 class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {stack<int> st;vector<int> result(nums1.size(), -1);if (nums1.size() 0) return result;unordered_map<int, …

去哪儿网机票服务请求体bella值逆向

作者声明&#xff1a;文章仅供学习交流与参考&#xff01;严禁用于任何商业与非法用途&#xff01;否则由此产生的一切后果均与作者无关&#xff01;如有侵权&#xff0c;请联系作者本人进行删除&#xff01; 一、加密定位 直接全局搜索bella&#xff0c;在可疑的地方下断&…

pandas学习笔记12

缺失数据处理 其实在很多时候&#xff0c;人们往往不愿意过多透露自己的信息。假如您正在对用户的产品体验做调查&#xff0c;在这个过程中您会发现&#xff0c;一些用户很乐意分享自己使用产品的体验&#xff0c;但他是不愿意透露自己的姓名和联系方式&#xff1b; 还有一些用…

使用C#和NMODBUS快速搭建MODBUS从站模拟器

MODBUS是使用广泛的协议&#xff0c;通讯测试时进行有使用。Modbus通讯分为主站和从站&#xff0c;使用RS485通讯时同一个网络内只能有一个主站&#xff0c;多个从站。使用TCP通讯时没有这方面的限制&#xff0c;可以同时支持多个主站的通讯读写。 开发测试时有各种复杂的需求&…

05 - 步骤 JSON output

简介 JSON Output 步骤用于将 Kettle 中的行流数据写出到 JSON 格式的文件或流中。它允许用户将 Kettle 中处理过的数据以 JSON 格式进行输出&#xff0c;适用于各种数据处理和交换场景。 什么是行流数据&#xff1f; preview data 中的每一个字段都是一个行流数据 使用 场…

54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接收发测试

工程代码https://download.csdn.net/download/txwtech/89258409?spm1001.2014.3001.5501 54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接收发测试 import socket from ohos.net.socket; import process from ohos.process; import wifiManager from ohos.wifiMana…

ton-http-api安装部署

1、拉取github代码 mkdir /data git clone https://github.com/toncenter/ton-http-api.git cd ton-http-api2、创建环境变量 ./configure.py cat .env TON_API_CACHE_ENABLED0 TON_API_CACHE_REDIS_ENDPOINTcache_redis TON_API_CACHE_REDIS_PORT6379 TON_API_CACHE_REDIS_T…

前后端分离实践:使用 React 和 Express 搭建完整登录注册流程

文章目录 概要整体架构流程技术名词解释ReactExpressReact RouterAnt Design 技术细节前端设计后端逻辑数据交互 小结 概要 本项目是一个基于React和Express的简单登录注册系统。通过前后端分离的方式&#xff0c;实现了用户的注册、登录和查看用户列表等功能。前端使用React框…

HCIP第二节

OSPF&#xff1a;开放式最短路径协议&#xff08;属于IGP-内部网关路由协议&#xff09; 优点&#xff1a;相比与静态可以实时收敛 更新方式&#xff1a;触发更新&#xff1a;224.0.0.5/6 周期更新&#xff1a;30min 在华为设备欸中&#xff0c;默认ospf优先级是10&#…

安居水站:《是谁毁掉了下一代?》

在时光的长河中&#xff0c;我们总能听到这样的声音。四十年前&#xff0c;人们惊恐地呼喊&#xff0c;武侠小说会毁掉下一代&#xff1b;三十年前&#xff0c;流行音乐被视为罪魁祸首&#xff1b;二十年前&#xff0c;电视节目背负起这沉重的指责&#xff1b;十年前&#xff0…

WWW‘24 | 课程学习CL+模仿学习IL用于ETF及商品期货交易

WWW24 | 课程学习CL模仿学习IL用于ETF及商品期货交易 原创 QuantML QuantML 2024-05-04 13:47 论文地址&#xff1a;[2311.13326] Curriculum Learning and Imitation Learning for Model-free Control on Financial Time-series (arxiv.org) 本文探讨了在金融时间序列数据上…

大聪明原理

原创 | 刘教链 不知不觉之间&#xff0c;BTC&#xff08;比特币&#xff09;快速完成了一个V形反转&#xff1a;从5月2日低开56.8k连涨3天&#xff0c;重回64k一线&#xff0c;已超过4月30日开盘价63k。反转的原因&#xff0c;在5.3教链内参《美就业数据爆冷门&#xff0c;BTC急…

Claude聊天机器人推出全新iOS客户端及团队专属计划

Anthropic 正在使其 Claude AI 更易于在移动设备上访问。该公司发布了适用于 iOS 的 Claude 移动应用程序,任何用户都可以免费下载。与聊天机器人的移动网络版本类似,该应用程序跨设备同步用户与 Claude 的对话,允许他们从计算机跳转到应用程序(反之亦然),而不会丢失聊天…

【信息收集-基于字典爆破敏感目录--御剑/dirsearch

两个工具都是内置字典来对于目录进行爆破的&#xff0c;这是信息收集的一部分&#xff0c;若能在列举出的目录中找到有价值的信息能为后续渗透做准备。 御剑比较简便 dirsearch需要集成python3.x环境&#xff0c;但是可选的命令更多。两者爆破的结果不一定相同&#xff0c;可以…

Linux课程机房虚拟机

Linux课程机房虚拟机 机房虚拟机&#xff08;默认不能联网的&#xff09;&#xff1a; 百度网盘&#xff1a;https://pan.baidu.com/s/1WqSvqB3Y7b_D4690CDBlJA?pwdaugc 123网盘&#xff1a;https://www.123pan.com/s/tQ0UVv-LiolA.html提取码:F4xm ‍ 联网使用说明&…

CC工具箱1.2.8更新_免费_90+工具

​CC工具箱1.2.8更新【2024.5.5】 使用环境要求&#xff1a;ArcGIS Pro 3.0 一、下载链接 工具安装文件及使用文档&#xff1a; https://pan.baidu.com/s/1OJmO6IPtMfX_vob3bMtvEg?pwduh5r 二、使用方法 1、在下载链接中下载安装文件【CC工具箱1.2.8.esriAddinX】&#xf…

回归测试的几种方法

回归测试&#xff0c;是对修复Bug后的软件进行验证&#xff0c;确保所有缺陷得到修复&#xff0c;并且没有引入新的Bug。 如果确保缺陷得到修复&#xff0c;那么只需要执行发现缺陷的测试用例&#xff0c;但这样不能排除引入新的Bug&#xff1b;而如果把所有测试用例都执行一遍…

fatal: fetch-pack: invalid index-pack output

解决方案&#xff1a;git clone --depth1 要克隆的git地址 下载最近一次提交的代码 其他分支的内容都不下载 这样整体下载体量就变小了 执行命令&#xff1a;git clone --depth 1 https://gitlab.scm321.com/ufx/xxxx.git

交叉导轨维护和保养的方法!

交叉导轨系统作为一种常见的机械传动装置&#xff0c;广泛应用于各种精密机械设备中。为了确保交叉导轨系统的正常运行和延长其使用寿命&#xff0c;定期维护和保养是至关重要的。 1、清洁&#xff1a;定期清理交叉导轨表面的灰尘、油污等杂质&#xff0c;保持其清洁。在清理过…

【LinuxC语言】setitimer与getitimer函数

文章目录 前言一、setitimer() 函数二、getitimer() 函数三、示例代码总结 前言 在Linux系统下&#xff0c;编写程序时经常需要使用定时器来实现一些定时任务、超时处理等功能。setitimer() 和 getitimer() 函数是两个用于操作定时器的重要函数。它们可以帮助我们设置定时器的…