数据结构刷题训练——链表篇(三)

目录

文章目录

前言

1. 题目一:环形链表Ⅱ

1.1 思路

1.2 分析

1.3 题解

1.4 方法二

2. 题目二:复制带随机指针的链表

2.1 思路

2.2 分析

2.3 题解

总结


前言

        在这个专栏博客中,我们将提供丰富的题目资源和解题思路,帮助读者逐步提高解题能力。同时,我们也将分享一些刷题技巧和经验,帮助读者更加高效地进行刷题训练。通过持之以恒的努力和不断的实践,相信读者可以在数据结构领域取得长足的进步。本期将是数据结构刷题训练链表篇的最后一期,后续我们将进入栈和堆的刷题训练。


1. 题目一:环形链表Ⅱ

题目描述:

示例:

 题目链接:环形链表Ⅱ

1.1 思路

        本题的题意是给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL。

        寻找第一个入环的节点,在上道环形链表的题目中仅仅只是判断是否有环,但没法确定入环的节点,这道题目属于之前题目的进阶。那我们要如何去解决呢?

        这里向大家说明一点,如果在刷题的时候,遇到一个题目,连题意都很难理解或者,是无从下手,那这道题目就不再是简简单单的考察代码能力,其中的分析更为重要,没有分析的过程,仅仅只要代码是无法看懂理解的。

1.2 分析

        初看题目毫无思路,但是别担心,我在分析之后记住这种做题思路、方法就可以,在后续刷题中灵活运用。这道题目我们仍然可以使用快慢指针的方法。

        首先我们需要知道带环链表的几种情况:

一般情况:

 环很大

 

 环很小

         在上期中我们将道使用快慢指针遍历链表,快指针一次走两步,慢指针一次走一步,如果它们相遇那它们一定是带环的链表。那问题来了,fast一次走两步,slow一次走一步,一定可以追上吗? 结论是一定能追上。

        为什么?我们可以分析一下,在两个指针都入环以后,快指针一次走两步,慢指针一次走一步,它们的距离会减一,一直走一直减一,最后直到追上,距离变化过程:

N

N-1

N-2

……

2

1

0

        那如果fast一次走3步,slow一次走两步呢?

        假设它们之间的距离是M,fast和slow都进环以后,它们的距离一次就是减2,那它们的距离变化:

M是偶数          M是奇数

M-2                  M-2

M-4                  M-4 

……                  ……

4                        3

2                        1

0                      -1

         如果M是偶数,就刚好追上相遇,如果M是奇数这就说明它们会错过,一旦错过就要继续走一圈,假设环的周长是C,当C为奇数时,当它们错过后,它们之间的距离是C-1,此时C-1必为偶数,下次一定能追上,但如果C是偶数时,C-1为奇数,然而它们每次距离减小2,这样无论怎么走都不会相遇。

         如果继续增大步数呢?fast一次走4步,slow一次走两步。假设进入环后它们的距离是k,那么它们的距离变化:

k是3的倍数          k%3=2            k%3=1

k-3                        k-3                  k-3

k-6                        k-6                   k-6

……                     ……                  ……

6                             5                     4

3                             2                     1

0                            -1                    -2

错过后距离:         C-1                 C-2

         如果C-1或C-2仍然不是3的倍数,那它们仍然始终无法相遇。有人可能会这样想,那让其中一个停下来,另一个去追不就可以了,但我们无法确定慢指针是否进环了,如果没进环,那快指针走多少圈都不会追上。这里只是移动步数的分析,在带环链表中使用快慢指针,最好使用步数差为1的,下面步入正题:

        依据上述结论,我们看这道题目,这里我们让fast一次走2步,slow一次走1步,当fast入环时:

        假设从起点到入环点距离为L,环周长为C

 慢指针入环时:

 

 相遇时:

         由上可以得出:fast走的距离时slow的二倍,那slow走的距离就是X+L,那fast走的路程就是L+X+n*C(n>=0),因为无法确定L于C的关系,如果C很小,那fast就可能走了很多圈。或许有人会疑惑,那slow为什么不用加n*C,因为slow入环以后,fast在slow走一圈之内一定能追上它

 我们根据这些关系可以得到:

L+X+n*C=2(L+X)

化简一下:

L+X=n*C

n*C-X=L

 得到n*C-X=L这个结论再转化一下就是:(n-1)*C+C-X=L

         到这里就一目了然了,一个指针从相遇点开始出发,一个从起点开始出发,最终它们会在入环点相遇。

1.3 题解

根据上述的分析进行编写代码:

struct ListNode *detectCycle(struct ListNode *head) 
{struct ListNode* slow,*fast;slow=fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){struct ListNode* meet=slow;while(meet!=head){head=head->next;meet=meet->next;}return head;}}return NULL;
}

1.4 方法二

        方法二的思路简单,但代码量增多,我们先让两指针相遇,相遇后将相遇的节点的next置为NULL,也就是将环断掉,这样就转化成了链表相交。

 代码如下:

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{struct ListNode* curA=headA,*curB=headB;int lenA=1,lenB=1;while(curA->next){curA=curA->next;lenA++;}while(curB->next){curB=curB->next;lenB++;}if(curA!=curB){return NULL;}int t= abs(lenA-lenB);struct ListNode* longlist=headA, *shortlist=headB;if(lenB>lenA){longlist=headB;shortlist=headA;}while(t--){longlist=longlist->next;}while(longlist!=shortlist){longlist=longlist->next;shortlist=shortlist->next;}return longlist;
}
struct ListNode *detectCycle(struct ListNode *head) 
{struct ListNode* slow,*fast;slow=fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){struct ListNode* meet=slow;struct ListNode* newnode=meet->next;meet->next=NULL;return getIntersectionNode(newnode,head);}}return NULL;
}

2. 题目二:复制带随机指针的链表

 题目描述:

 示例:

 题目链接:

复制带随机指针的链表

2.1 思路

        或许大部分人读完题目还是像上道题目一样,读完没有思路,甚至连题意都读不懂。

        复制一个链表不难,但这道题目的难点在于每个节点指针域的随机指针,我们很难控制随机指针的指向,单纯的完全复制行不通,复制下来的节点关系要与原链表相同,这才是本道题目的难点。

怎么才能找到随机指针的指向关系呢?

我们的思路是这样的:

  • 遍历原链表,遍历一个节点复制一个节点,然后将复制的节点插入道原节点的后边。
  • 再次遍历插入后的链表,找复制节点的随机指针的指向关系。
  • 最后将复制的链表与原链表分开

2.2 分析

 根据思路进行分析:

 复制后的链表链接道原链表

 这里要理解如何去找复制节点的random指向的节点。

我们可以这样操作:copy->random=cur->random->next

         重点就是这句的理解,cur指向的是原链表中的节点,复制的也就是cur指向的节点,然后将复制的节点(copy)链接到cur节点后,那copy节点的random不就在cur节点的random指向节点的下一个吗?

        意思就是说,遍历原链表中的节点,找到当前节点的random就可以找到复制节点的random,因为复制节点(copy)的random,就是当前节点(原链表)random指向节点的下一个节点。

         这里要好好理解,例如:13号这个节点(cur),13节点的下一个节点就是复制的13号节点。cur的random指向的是7号节点(原链表),7号节点的下一个节点不就是复制的13号节点(copy)要找的random吗?

        但这里需要特殊处理一种情况,就是原链表random指向为NULL的情况,这里就直接将复制节点的random置为NULL。

2.3 题解

根据上述的分析,开始编写代码:

struct Node* copyRandomList(struct Node* head)
{struct Node* cur=head;while(cur)                    //复制节点{struct Node* copynode=(struct Node*)malloc(sizeof(struct Node));struct Node* next=cur->next;copynode->val=cur->val;//插入到原节点后cur->next=copynode;copynode->next=next;cur=next;}cur=head;//寻找复制节点的randomwhile(cur)        {struct Node* copynode=cur->next;if(cur->random==NULL)        //随机指针为NULL进行特殊处理{copynode->random=NULL;}else{copynode->random=cur->random->next;}cur=cur->next->next;}cur=head;struct Node* copyhead,*copytail;copyhead=copytail=NULL;//还原原节点,将两个链表分开while(cur){struct Node* copynode=cur->next;struct Node* next=cur->next->next;//将复制节点链接到新的链表,这里使用的是无头节点的链表,所有需要特殊处理if(copyhead==NULL){copyhead=copytail=copynode;}else{copytail->next=copynode;copytail=copytail->next;}//恢复原链表cur->next=next;cur=next;}return copyhead;
}


 

总结

        本期的题目相对较为复杂,希望大家能够好好的消化理解,最后,感谢你的阅读和支持。希望你在这个数据结构的学习旅程中能够获得满满的收获和成就感。愿我们共同努力,不断探索和挑战,成为数据结构领域的行家里手!

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

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

相关文章

Flutter(八)事件处理与通知

1.原始指针事件处理 一次完整的事件分为三个阶段:手指按下、手指移动、和手指抬起,而更高级别的手势(如点击、双击、拖动等)都是基于这些原始事件的。 Listener 组件 Flutter中可以使用Listener来监听原始触摸事件 Listener({…

The Sandbox 与 D.OASIS 联手打造 D.OASIS 城市

我们非常高兴地宣布与 D.OASIS 建立合作伙伴关系,共同打造无与伦比的娱乐体验:The Sandbox 中的 D.OASIS 城市! 作为合作的一部分,The Sandbox 和D.OASIS将共同打造 D.OASIS 城市,一座充满无限可能的大都市&#xff0…

TDengine + Telegraf + Grafana 实现图形化服务器状态监控

TDengine Telegraf Grafana 实现图形化服务器状态监控 技术栈环境搭建安装tdenginue下载安装包解压文件运行安装文件启动td运行 taosAdapter 安装Telegraf添加yum源安装生成配置文件修改配置文件启动telegraf 安装Grafana直接yum安装安装td数据源配置启动Grafana配置数据源导…

CentOS 7中,配置了Oracle jdk,但是使用java -version验证时,出现的版本是OpenJDK,如何解决?

1.首先,检查已安装的jdk版本 sudo yum list installed | grep java2.移除、卸载圈红的系统自带的openjdk sudo yum remove java-1.7.0-openjdk.x86_64 sudo yum remove java-1.7.0-openjdk-headless.x86_64 sudo yum remove java-1.8.0-openjdk.x86_64 sudo yum r…

安卓:MMKV——键值存储库

目录 一、MMKV介绍 1.特点和优势: 2.使用指南: 3.依赖包: 二、MMKV的常用方法 1、初始化和获取实例: 2、存储数据: 3、读取数据 4、删除数据 5、其他操作: 三、MMKV的使用例子 MainActivity&#xff…

文件上传漏洞(webshell)

一、防护 1、防护 1、判断文件后缀,为图片的话才让上传成功。 2、解析文件内容(文件幻数)判断文件头和文件尾部是否一致 幻数 常见的 3、隐藏按钮(带上code唯一值) 4、二次渲染(类似拿着你的图片&#xff…

super父类 事物

一个没有事物的方法。 调用他的父类里有事物的方法。 无论this 和 super 都会让父类事物方法没有事物。 如果写了super.class 文件里面,就是super调用。 如果没写,就是this调用,坑爹 测试,把父类注入,事物才生效。

kubeasz在线安装K8S集群单master

1.基础系统配置 确保在干净的系统上开始安装,不能使用曾经装过kubeadm或其他k8s发行版的环境 系统是Ubuntu 或者CentOS 7 2.下载文件 2.1 下载工具脚本ezdown,举例使用kubeasz版本3.5.0 #此版本默认安装的是 K8S v1.26.0 export release3.5.0 wget h…

[免费在线] 将 PDF 转换为 Excel 或 Excel 转换为 PDF | 5 工具

有了免费的在线 PDF 转换器,您可以轻松免费在线将 PDF 转换为 Excel 或 Excel 转换为 PDF。这篇文章为您筛选了 5 个最常用的工具。要从存储介质恢复错误删除或丢失的 PDF 文档、Excel 电子表格、Word 文件或任何其他文件,您可以使用免费的数据恢复程序 …

DOM基础获取元素+事件基础+操作元素

一.DOM简介 DOM,全称“Document Object Model(文档对象模型)”,它是由W3C定义的一个标准。 在实际开发中,我们有时候需要实现鼠标移到某个元素上面时就改变颜色,或者动态添加元素或者删除元素等。其实这些效…

Python爬虫(八)_Requests的使用

Requests:让HTTP服务人类 虽然Python的标准库中urllib2模块中已经包含了平常我们使用的大多数功能,但是它的API使用起来让人感觉不太好,而Requests自称"HTTP for Humans",说明使用更简单方便。 Requests唯一的一个非转…

一周 AIGC 丨苹果下架多款 AIGC 应用,阿里云开源通义千问 70 亿参数模型

多个 AIGC 应用在苹果应用商店下架,包含数据采集和使用不够规范等问题。阿里云开源通义千问 70 亿参数模型,包括通用模型 Qwen-7 B 和对话模型 Qwen-7 B-Chat。腾讯混元大模型开始应用内测,内部多个业务线接入测试。百度智能云“千帆大模型平…

【PostgreSQL内核学习(十一)—— OpenGauss源码学习(CopyTo)】

可优化语句执行 概述什么是列存储?列存的优势 相关函数CopyToCStoreCopyToCopyStatetupleDescCStoreScanDesc CStoreBeginScanRelationSnapshotProjectionInfo GetCStoreNextBatchRunScanFillVecBatchCStoreIsEndScan CStoreEndScan 声明:本文的部分内容…

54款宝藏级AIGC工具分享(claude,Midjourney,Stable Diffusion等)

随着ChatGPT的一波又一波高潮,生成式AI逐渐进入人们视野,并开始大行其道,正如人们所说:AI用的好,天天下班早! 当然,有效的利用AI不但能下班早,还能在上班时间摸鱼,就如潘…

【web逆向】全报文加密流量的去加密测试方案

aHR0cHM6Ly90ZGx6LmNjYi5jb20vIy9sb2dpbg 国密混合 WEB JS逆向篇 先看报文:请求和响应都是全加密,这种情况就不像参数加密可以方便全文搜索定位加密代码,但因为前端必须解密响应的密文,因此万能的方法就是搜索拦截器&#xff0c…

0基础学习VR全景平台篇 第78篇:全景相机-拍摄VR全景

新手入门圆周率科技,成立于2012年,是中国最早投身嵌入式全景算法研发的团队之一,亦是全球市场占有率最大的全景算法供应商。相继推出一体化智能屏、支持一键高清全景直播的智慧全景相机--Pilot Era和Pilot One,为用户带来实时畅享…

【个人记录】CentOS7 编译安装最新版本Git

说明 使用yum install git安装的git版本是1.8,并不是最新版本,使用gitlab-runner托管时候会拉项目失败,这里使用编译源码方式安装最新版本的git。 基础环境安装 echo "nameserver 8.8.8.8" >> /etc/resolv.conf curl -o /…

算法基础之插入排序

1、插入排序基本思想 插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序)&a…

【论文阅读】UNICORN:基于运行时来源的高级持续威胁检测器(NDSS-2020)

UNICORN: Runtime Provenance-Based Detector for Advanced Persistent Threats NDSS-2020 哈佛大学 Han X, Pasquier T, Bates A, et al. Unicorn: Runtime provenance-based detector for advanced persistent threats[J]. arXiv preprint arXiv:2001.01525, 2020. 源码&…

vue3 excel 导出功能

1.安装 xlsx 库 npm install xlsx2.创建导出函数 src/utils/excelUtils.js import * as XLSX from xlsx;const exportToExcel (fileName, datas, sheetNames) > {// 创建工作簿const wb XLSX.utils.book_new()for (let i 0; i < datas.length; i) {let data datas…