链表算法题(下)
在链表算法题(上)长中我们已经学习了一系列的链表算法题,那么在本篇中我们将继续来学习链表的算法题,接下来就继续来破解链表的算法题吧!

1.相交链表
160. 相交链表 - 力扣(LeetCode)

通过以上的题目的描述该算法题要我们实现的代码功能是判断两条链表是否相交,如果相较的话就返回相较节点的指针,不相较就返回NULL
那么在实现该算法题的代码之前先要来分析如何实现判断是否是相交链表
首先来看相交链表有什么特征呢?来看以下的示例
从以上的示例就可以看出当两个链表是相交的,那么在这两条链表内一定会有两个节点的下一个节点是相同的。而如果链表不是相交的,那么就不会有两个节点的下一个节点是相同的
当两个链表是相较的时候我们需要返回的就是以上这个节点,那么该如何来找出这个相交的节点呢?
在此我们的解决方法是先定义两个指针变量一开始分别指向两个链表的第一个节点,之后通过各遍历一次两条链表,之后就得到这两条链表各自的节点个数,之后将得到的两个节点数大的减小的得到两链表长度的差值,将节点个数多的链表的定义的节点指针往后走之前得到的差值,最后将两个链表的指针同时往后遍历,当两个指针相同时就说明这两个链表为相交链表,否则就不相交
例如以下示例:
首先A链表个数为5,B节点个数为6,两个链表节点差值就为1
在定义两个指向两个;链表的第一个节点的指针pcur1和pcur2,由于B链表为节点个数多的链表因此将B链表的指针pcur2先向后走1步
之后让pcur1和pcur2同时向后遍历,之后pcur1和pcur2同时指向c1节点,这就可以说明A和B这两个链表是相交链表
接下来我们就来实现该算法题的代码
在以下得到两个链表的节点数差值使用的是库函数abs,该函数能计算出差值的绝对值
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/
typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{ListNode* pcur1=headA;ListNode *pcur2=headB;int count1=0;int count2=0;while(pcur1)//得到第一个链表的结点数{count1++;pcur1=pcur1->next;}while(pcur2)//得到第二个链表的节点数{count2++;pcur2=pcur2->next;}int tmp=abs(count1-count2);//得到两个链表节点数的差值ListNode* longlist=headA;ListNode* shortlist=headB;if(count1<count2)//确定长短链表{longlist=headB;shortlist=headA;}while(tmp--)//先将长链表走tmp步{longlist=longlist->next;}while(longlist && shortlist)//同时遍历两个链表{if(longlist==shortlist){return longlist;}longlist=longlist->next;shortlist=shortlist->next;}return NULL;
}
2.环形链表I
141. 环形链表 - 力扣(LeetCode)

根据以上的题目描述就可以看出该算法题要我们实现的是判断链表是否为循环链表,在此循环链表是指链表的尾节点不在是连接NULL,而是连接链表中的其中一个节点
那么使用什么方法能判断链表是否为循环链表呢?
在此我们使用的是之前学习过的前后指针法,首先定义有两个指针变量fast和slow,之后fast指针每次走两步,slow指针每次走一步,到最后如果fast指针和slow相遇就说明该链表为循环链表
例如以下示例:
要判断以上链表是否为循环链表我们来看看使用前后指针法的过程是什么样的,首先定义快指针fast和满指针slow,之后让fast和slow遍历链表
正如上图所示slow指针和fast指针在节点-4相遇,这就说明该链表为循环链表为循环链表
接下来我们就来实现该算法题的代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head)
{ListNode* fast,*slow;fast=slow=head;while(fast && fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){return true;}}return false;
}
在解决了以上的算法题后我们就要思考为什么快指针每次走两步,慢指针走一步可以相遇,有没有可能遇不上呢?
slow一次走⼀步,fast一次走2步,fast先进环,假设slow也走完入环前的距离,准备进环,此时fast和slow之间的距离为N,接下来的追逐过程中,每追击⼀次,他们之间的距离缩小1步
这时在追击过程中fast和slow之间的距离变化:
因此,在带环链表中慢指针走一步,快指针走两步最终一定会相遇。
那么在解决以上问题后思考快指针一次走3步,走4步,...n步行吗?
step1:
按照上面的分析,慢指针每次走一步,快指针每次走三步,此时快慢指针的最大距离为N,接下来的追逐过程中,每追击一次,他们之间的距离缩小2步
追击过程中fast和slow之间的距离变化:
分析:
1、如果N是偶数,第一轮就追上了
2、如果N是奇数,第一轮追不上,快追上,错过了,距离变成-1,即C-1,进入新的一轮追击
a:C-1如果是偶数,C-1如果是偶数,那么下一轮就追上了
b:C-1如果是奇数,那么就永远都追不上
总结一下追不上的前提条件:N是奇数,C是偶数step2:
在以上的step1中我们得出当fast追不上的前提条件:N是奇数,C是偶数,那么接下来我们就要继续分析这种情况是否会出现
假设:
环的周长为C,头结点到slow结点的长度为L,slow走一步,fast走三步,当slow指针入环后,slow和fast指针在环中开始进行追逐,假设此时fast指针已经绕环x周。
在追逐过程中,快慢指针相遇时所走的路径长度:
由于慢指针走一步,快指针要走三步,因此得出: 3 * 慢指针路程 = 快指针路程 ,即:
对上述公式继续分析:由于偶数乘以任何数都为偶数,因此 2L 一定为偶数,则可推导出可能得情
况:
• 情况1:偶数 = 偶数 - 偶数
• 情况2:偶数 = 奇数 - 奇数由step1中(1)得出的结论,如果N是偶数,则第一圈快慢指针就相遇了。
由step1中(2)得出的结论,如果N是奇数,则fast指针和slow指针在第一轮的时候套圈了,开始进行下一轮的追逐;当N是奇数,要满足以上的公式,则 (x+1)C 必须也要为奇数,即C为奇数,满足(2)a中的结论,则快慢指针会相遇因此, step1 中的 N是奇数,C是偶数不成立,既然不存在该情况,则快指针一次走3步最终一定也可以相遇。
因此快指针一次走4、5.....步最终也会相遇,其证明方式同上
注:虽然已经证明了快指针不论走多少步都可以满足在带环链表中相遇,但是在编写代码的时候会有额外的步骤引入,涉及到快慢指针的算法题中通常习惯使用慢指针走⼀步快指针走两步的方式。
3.环形链表II
142. 环形链表 II - 力扣(LeetCode)

在以上环形链表I中我们已经实现了如何判断一个链表是否为环形链表,接下来我们在环形链表算法题中我们将跟进一步当链表是环形链表时我们还要返回链表进入环的第一个节点
那么要如何才能找到环形链表进入环的第一个节点呢?接下来我们要来了解一个性质
让一个指针从链表起始位置开始遍历链表,同时让⼀个指针从判环时相遇点的位置开始绕环运
行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
例如以下示例:
根据使用快慢指针法我们就可以的到以上链表两指针的相遇节点为-4
在此之后我们再定义一个指针变量pcur指向链表的第一个节点,之后让pcur指针和fast指针同时遍历,当这两个指针指向同一个节点时,指针指向的节点就是入环前的节点
接下来我们就来实现该算法题的代码
/*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head)
{ListNode* fast,*slow;fast=slow=head;while(fast&& fast->next){fast=fast->next->next;slow=slow->next;if(slow==fast){ListNode* pcur=head;while(pcur!=fast){pcur=pcur->next;fast=fast->next;}return fast;}}return NULL;
}
在解决了以上的算法题后我们就要证明为什么在环形链表中以上的这种性质:
在以上图示当中H为链表的起始点,E为环入口点,M与判环时候相遇点
在此我们设环的长度为R,H到E的距离为L,E到M的距离为 X ,则:M到E的距离为 R-X
由于快指针和满指针走过的路径分别为
又因为快指针走过的路径长度为满指针走过的路径长度的两倍,这时就能得到以下的公式
根据以上公式就可以推断出以下公式:
在此可以继续得到
当慢指针进入环时,快指针可能已经在环中绕了n圈了,n⾄少为1因为:快指针先进环走到M的位置,,最后又在M的位置与慢指针相遇
所以以上公式n可能为1,2,3,4......,n的大小取决于环的大小,环越小n越大,在此极端情况下,假设n=1,此时: L=R-X
根据L=R-X即可说明:⼀个指针从链表起始位置运行,⼀个指针从相遇点位置绕环,每次都走⼀步,两个指针最终会在入口点的位置相遇
4.随机链表的复制
138. 随机链表的复制 - 力扣(LeetCode)

根据以上的题目描述可以看出该算法题和我们之前解决的题不同,在该算法题中的链表节点中的有三个成员变量,相比正常的链表节点多了一个随机的指针random。在此题目要我们实现的是链表的拷贝,注意在此不是将原链表内的指针复制一份,这种只是浅拷贝,在此算法题中我们要实现的是深拷贝,也就是要额外开一份和原链表一样的内存空间,在将原链表内的数据拷贝给新的链表
接下来我们就来分析如何来实现链表的拷贝
例如以下示例:
在以上链表中若要实现链表的拷贝,那么该如何实现呢?
在此你可能会想到可以通过遍历原链表,在每遍历到一个节点时就创建一个新的节点,再将原链表节点内的数据拷贝给新节点,之后再将新节点尾插新链表
但是在以上的示例按照这种方法来实现就会发现问题了,在以上示例的链表按照以上的方法来拷贝在第一个节点时没问题,当到了第二个节点就出现一个问题就是原链表第二个节点中的random指针指向的第一个节点,但在使用以上方法时第二个节点中的random无法找到第一个节点,这时因为单向链表中无法向前遍历链表
因此要解决链表的拷贝以上的方法行不通,在此我们需要想其他的方法
接下来就来讲解一种很妙的方法首先是在原链表基础上复制链表
在此我们先定义两个指针变量pcur和Next分别指向原链表第一个节点和第二个节点
之后创建一个新的节点并且将第一个节点内的值val拷贝到新节点中,再将新节点插入到pcur和Next节点中间,完成以上操作后让pcur指向Next指向的节点,Next指向其next指针指向的节点
之后在遍历原链表每个节点时重复以上的操作,直到pcur指向NULL停止操作,这时原链表就变为以下形式
在以上我们创建的新节点只进行了val的拷贝,那么接下来就来对random来进行拷贝,要进行random的拷贝接下来要再创建一个指针变量copy让其一开始指向创建的第一个新节点,并且之后还要让pcur和Next指针重新回到初始位置
之后继续置random指针
在此pcur指向节点的random为NULL,就让这时copy指向的节点内的random也置为NULL,之后让pcur指向Next指向的节点,Next指向其next指针的next指向的节点,copy指向改变后的pcur的next指针指向的节点
之后再遍历原链表,当pcur指向节点内的random不为NULL时,让copy内的random指针指向pcur内random指向的节点next指针指向的节点,也就是copy->random=pcur->random->next,最后当pcur为NULL停止,这时原链表就变为以下形式
完成以上操作后最后就要将原链表和赋值链表断开
在此让pcur的next指针指向copy的next指针指向的节点,copy的next指针指向pcur的next指针指向的节点next指针指向的节点,之后让copy和pcur都往后走一步
之后再遍历原链表,重复以上的操作,这时原链表就变为以下形式
通过以上示例的讲解就可以发现链表的复制分为以下3步:

接下来就来实现该算法题的代码
/*** Definition for a Node.* struct Node {* int val;* struct Node *next;* struct Node *random;* };*/typedef struct Node Node;Node* NewNode(int x){Node* newnode=(Node*)malloc(sizeof(Node));newnode->val=x;newnode->next=newnode->random=NULL;return newnode;}struct Node* copyRandomList(struct Node* head)
{if(head==NULL){return head;}Node* pcur=head;
//在原链表基础上复制链表while(pcur){Node* Next=pcur->next;Node*newnode=NewNode(pcur->val);newnode->next=Next;pcur->next=newnode;pcur=pcur->next->next;}
//置random指针pcur=head;while(pcur!=NULL){Node* newpcur=pcur->next;if(pcur->random!=NULL){newpcur->random=pcur->random->next;}pcur=newpcur->next;}
//将原链表和赋值链表断开pcur=head;Node* newhead,*newptail;newhead=newptail=pcur->next;while(pcur->next->next){pcur=pcur->next->next;newptail->next=pcur->next;newptail=newptail->next;}return newhead;
}
以上就是链表算法题的全部内容了,希望能得到你的点赞、收藏
相关文章:
链表算法题(下)
在链表算法题(上)长中我们已经学习了一系列的链表算法题,那么在本篇中我们将继续来学习链表的算法题,接下来就继续来破解链表的算法题吧! 1.相交链表 160. 相交链表 - 力扣(LeetCode) 通过以上…...
UE4_后期处理_后期处理材质及后期处理体积二
效果: 步骤: 1、创建后期处理材质,并设置参数。 2、回到主界面,找到需要发光的物体的细节面板。 渲染自定义深度通道,默认自定义深度模具值为10(需要修改此值,此值影响物体的亮度)。 3、添加…...
Linux系统与高效进程控制的实战技巧
Linux系统与高效进程控制的实战技巧 Linux,作为一种开源的Unix-like操作系统内核,自1991年由芬兰程序员Linus Torvalds首次发布以来,已成为全球范围内广泛使用的操作系统之一。其强大的功能、灵活的配置以及高度的可定制性,使得L…...
陈文自媒体:抖音创作者伙伴计划,你不知道的几点!
本月的2号开始,官方就下达了通知,各位西瓜创作者,大家要抓紧时间升级为抖音创作者伙伴计划,如果你不升级是吧,没问题,19号开始不发西瓜和中视频收益了。 在这个政策解读和操作过程中,我从同行、…...
便携式气象仪器的主要特点
TH-BQX9】便携式气象仪器,也称为便携式气象仪或便携式自动气象站,是一款高度集成、低功耗、可快速安装、便于野外监测使用的高精度自动气象观测设备。以下是关于便携式气象仪器的详细介绍: 主要特点 高精度与多功能:便携式气象仪器…...
【开源风云】从若依系列脚手架汲取编程之道(四)
📕开源风云系列 🍊本系列将从开源名将若依出发,探究优质开源项目脚手架汲取编程之道。 🍉从不分离版本开写到前后端分离版,再到微服务版本,乃至其中好玩的一系列增强Plus操作。 🍈希望你具备如下…...
华为 HCIP-Datacom H12-821 题库 (15)
有需要题库的可以看主页置顶 1.以下关于 OSPF 路由聚合的描述,错误的是哪一项? A、OSPF 中任意一台路由器都可以进行路由聚合的操作 B、OSPF 有两种路由聚合方式:ABR 聚合和ASBR 聚合 C、路由聚合是指将相同前缀的路由信息聚合一起…...
MT6895(天玑8100)处理器规格参数_MTK联发科平台方案
MT6895平台 采用台积电5nm工艺,与天玑 8000 相比性能提升 20% ,搭载4 个 2.85GHz A78 核心 4 个 2.0GHz A55 核心,CPU能效比上一代提高 25% 。GPU 采用了第三代的Valhall Arm Mali-G610 MC6架构,拥有6核心,搭配天玑81…...
从 0 开始搞定 RAG 应用系列(第一篇):构建简单 RAG
从 0 开始搞定 RAG 应用系列(第一篇):构建简单 RAG 前言 LLM 已经从最初的研究性转变为实际应用性,尤其在今年各大 LLM 厂商都在研究 LLM 的商业化落地方案(包括我司)。而在各种商业化场景中个人觉得最具…...
接口(Interface)和端点(Endpoint)的区别
在软件开发和相关的文档中,我们经常会看到两个专有名词:接口(Interface)和端点(Endpoint)。而它们的使用场景有很大的重合部分,让人有些分不清到底用哪个。那么,这两者到底有什么区别…...
小米汽车再陷“抄袭”争议,上汽高管直言“真不要脸”
小米SU7在上市初期就曾面临来自各方的争议与质疑,不少人将其戏称为“米时捷”或“保时米”。 转载科技新知 原创 作者丨杰瑞 编辑丨影蕨 近日,在成都车展上,上汽乘用车常务副总经理俞经民对小米汽车提出了尖锐批评,指责其“抄袭”…...
VS C++ 加入dump实现崩溃日志 可以再崩溃的时候使用VS调试
调用 // 加入崩溃dump文件功能SetUnhandledExceptionFilter(ExceptionFilter); 实现 #include "DbgHelp.h"//生成dump int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers) {// 定义函数指针typedef BOOL(WINAPI * MiniDumpWriteDumpT)(HANDLE,DWORD,H…...
Ubuntu22.04版本左右,开机自动启动脚本
Ubuntu22.04版本左右,开机自动启动脚本 1. 新增/lib/systemd/system/rc-local.service中[Install]内容 vim /lib/systemd/system/rc-local.service 按 i 进入插入模式后,新增内容如下: [Install] WantedBymulti-user.target Aliasrc-local.…...
中秋之美——html5+css+js制作中秋网页
中秋之美——html5cssjs制作中秋网页 一、前言二、功能展示三、系统实现四、其它五、源码下载 一、前言 八月十五,秋已过半,是为中秋。 “但愿人长久,千里共婵娟”,中秋时节,气温已凉未寒,天高气爽&#x…...
java设计模式day03--(结构型模式:代理模式、适配器模式、装饰者模式、桥接模式、外观模式、组合模式、享元模式)
5,结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。 由于组合关系或聚合关系比继承关系耦合度低,满足“…...
Golang path/filepath包详解:高效路径操作与实战案例
Golang path/filepath包详解:高效路径操作与实战案例 引言基础用法Abs 函数Base 函数Clean 函数Dir 函数Ext 函数FromSlash 和 ToSlash 函数 基础用法Abs 函数Base 函数Clean 函数Dir 函数Ext 函数FromSlash 和 ToSlash 函数 路径操作Join 函数Split 函数Rel 函数Ma…...
【Shiro】Shiro 的学习教程(四)之 SpringBoot 集成 Shiro 原理
目录 1、第一阶段:启动服务,构建类的功能2、第二阶段:正式请求 1、第一阶段:启动服务,构建类的功能 查看 Shiro 配置类 ShiroConfiguration: Configuration public class ShiroConfiguration {// 创建 sh…...
多线程篇(阻塞队列- PriorityBlockingQueue)(持续更新迭代)
目录 一、简介 二、类图 三、源码解析 1. 字段讲解 2. 构造方法 3. 入队方法 put 浮调整比较器方法的实现 入队图解 4. 出队方法 take dequeue 下沉调整比较器方法的实现 出队图解 四、总结 一、简介 PriorityBlockingQueue队列是 JDK1.5 的时候出来的一个阻塞…...
strstr函数的使用和模拟实现
目录 1.头文件 2.strstr函数的使用 3.strstr函数模拟实现 小心!VS2022不可直接接触,否则!没这个必要,方源面色淡然一把抓住!顷刻炼化! 1.头文件 strstr函数的使用需要头文件 #include<string.h>…...
使用Selenium与WebDriver实现跨浏览器自动化数据抓取
背景/引言 在数据驱动的时代,网络爬虫成为了收集和分析海量数据的关键工具。为了应对不同浏览器环境下的兼容性问题,Selenium与WebDriver成为了开发者实现跨浏览器自动化数据抓取的首选工具。本文将深入探讨如何利用Selenium和WebDriver实现跨浏览器的数…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...



之后让pcur1和pcur2同时向后遍历,之后pcur1和pcur2同时指向c1节点,这就可以说明A和B这两个链表是相交链表












之后创建一个新的节点并且将第一个节点内的值val拷贝到新节点中,再将新节点插入到pcur和Next节点中间,完成以上操作后让pcur指向Next指向的节点,Next指向其next指针指向的节点




