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

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实现跨浏览器的数…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...



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












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




