当前位置: 首页 > news >正文

【数据结构】第四站:单链表力扣题(二)

目录

一、链表的回文结构

二、相交链表

三、环形链表

四、环形链表Ⅱ

五、复制带随机指针的链表


一、链表的回文结构

题目描述:链表的回文结构_牛客题霸_牛客网

对于这道题,如果没有前面的一些题的基础,是非常难做的,我们的思路是这样的,先找到链表的中间结点,然后从中间结点开始将后半段链表逆置,然后依次比较即可。所以这里就需要复用前面题目的函数了,代码如下所示

/*
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:struct ListNode* middleNode(struct ListNode* phead){struct ListNode* fast=phead;struct ListNode* slow=phead;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;}return slow;}struct ListNode* reverse(struct ListNode* phead){struct ListNode* prev=NULL;struct ListNode* cur=phead;while(cur!=NULL){struct ListNode* next=cur->next;cur->next=prev;prev=cur;cur=next;}return prev;}bool chkPalindrome(ListNode* A) {// write code herestruct ListNode* phead=A;struct ListNode* middle=middleNode(phead);struct ListNode* NewHead=reverse(middle);struct ListNode* cur1=phead;struct ListNode* cur2=NewHead;while(cur2!=NULL){if(cur1->val==cur2->val){cur1=cur1->next;cur2=cur2->next;}else{return false;}}return true;}
};

二、相交链表

题目链接:力扣

对于这道题,我们可以采用最简单的双层暴力循环做出来。但是那样效率太低,我们其实可以先算出两个链表的长度,然后让长的链表都差值步,最后两个链表一块走,如果遇到两个结点的地址相同,那么就是相交的位置

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* cur1=headA;struct ListNode* cur2=headB;int len1=0;int len2=0;while(cur1){len1++;cur1=cur1->next;}while(cur2){len2++;cur2=cur2->next;}cur1=headA;cur2=headB;if(len1>len2){int len=len1-len2;while(len--){cur1=cur1->next;}}else{int len=len2-len1;while(len--){cur2=cur2->next;}}while(cur1!=cur2){cur1=cur1->next;cur2=cur2->next;}return cur1;
}

三、环形链表

题目链接:力扣

对于这道题,我们可以采用快慢指针法来完成,试想一下,让快指针走两步,慢指针走一步,那么当慢指针走到环的入口的时候,快指针一定在环里面走了一段距离了,而每次快指针与满指针的距离都会缩短一步。那么一定会追的上。最终代码如下所示

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
bool hasCycle(struct ListNode *head) {struct ListNode* fast=head;struct ListNode* slow=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){return true;}}return false;
}

然而,我们在这里会思考一个问题,慢指针走一步,快指针走两步,如果带环,最后一定可以相遇吗,如果快指针走三步四步呢?

对于这个问题,我们需要好好思考一下。我们假定下面这样一个带环的链表

当fast走进环入口的时候,slow正好走到一半

当slow走到入口的时候,fast已经在环内某个位置了,我们不妨记作此时fast距离slowN步这样的话,由于距离每次减少1。所以N最终一定会减到0。所以会相遇

那么如果是fast一次三步呢?

我们还是上图进行分析

对于现在相差N步,由于每次距离减少2

所以当N为偶数的时候,一定会减为0

当N为奇数的时候,这时候fast就最终一定会超越slow一步,此时进入新一轮的追击

我们设周长为C,那么fast需要追C-1步

 这样的话当C-1为偶数的话,自然追的上,C-1为奇数的话,则永远也不可能追的上

当fast为一次走四步的时候也是同理的。

在这里我们或许还会碰到一个新的问题,如何计算环的长度,这个思路其实也很简单,我们只需要求出相遇点,然后让一个指针不动,另外一个指针一直走然后计数即可。当回到相遇点的时候,正好就是环的长度

四、环形链表Ⅱ

题目链接:力扣

对于这道题,我们可能就比较难以思考了。

我们的分析过程是这样的:

由于是环形链表,那么我们可以求出他的相遇点,既然有了相遇点。我们继续设相遇点与入口的距离为X,头节点与入口点的距离为L

 然后我们计算fast和slow两个指针在相遇的瞬间他们已经走的距离

fast的距离为L+N*C+X,其中N大于等于1。因为fast先入环需要追击一圈

slow的距离为L+X

注意这里slow在环内所走的路程一定不超过一圈,即0<=X<C,这是因为fast的速度是slow的二倍,假如fast追赶slow所需要的路程不超过C-1,由于相对速度为1,那么slow所走的路程就不超过C-1。

由于fast的速度是slow的二倍,所以fast的路程是slow的二倍。

所以 L+N*C+X=2(L+X)

可以得出,L=N*C-X

为了方便理解可以进一步化简为:L=(N-1)*C-X

这个公式的物理意义就是,一个指针从头结点开始走,一个指针从相遇点走,那么必然相遇于入口。代码为

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* fast=head;struct ListNode* slow=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){struct ListNode* meet=fast;while(meet!=head){meet=meet->next;head=head->next;}return meet;}}return NULL;
}

其实对于这道题,还有另外一种思路,我们可以将相遇点和相遇点的下一个结点断开,然后让相遇点的下一个结点作为头结点,这样就转化为了相交链表的问题

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode* cur1=headA;struct ListNode* cur2=headB;int len1=0;int len2=0;while(cur1){len1++;cur1=cur1->next;}while(cur2){len2++;cur2=cur2->next;}cur1=headA;cur2=headB;if(len1>len2){int len=len1-len2;while(len--){cur1=cur1->next;}}else{int len=len2-len1;while(len--){cur2=cur2->next;}}while(cur1!=cur2){cur1=cur1->next;cur2=cur2->next;}return cur1;
}
struct ListNode *detectCycle(struct ListNode *head) {struct ListNode* fast=head;struct ListNode* slow=head;while(fast&&fast->next){fast=fast->next->next;slow=slow->next;if(fast==slow){struct ListNode* meet=fast;struct ListNode* list1=meet->next;struct ListNode* list2=head;meet->next=NULL;return getIntersectionNode(list1,list2);}}return NULL;
}

五、复制带随机指针的链表

题目链接:力扣

解法一

对于这道题,我们有一种比较简单的思路,直接暴力求解。

具体思路是首先将普通的链表拷贝下来。先不处理random指针。这个比较简单

然后,我们开始处理random,对于random我们只能采用相对位置来进行记录。这样的话,时间复杂度达到了O(N²)

我们直接给出代码

/*** Definition for a Node.* struct Node {*     int val;*     struct Node *next;*     struct Node *random;* };*/struct Node* copyRandomList(struct Node* head) {struct Node* copyhead=NULL;struct Node* copytail=NULL;struct Node* cur=head;while(cur){struct Node* copy=(struct Node*)malloc(sizeof(struct Node));copy->val=cur->val;copy->next=NULL;if(copyhead==NULL){copyhead=copytail=copy;}else{copytail->next=copy;copytail=copy;}cur=cur->next;}cur=head;struct Node* copycur=copyhead;while(cur){if(cur->random==NULL){copycur->random=NULL;copycur=copycur->next;}else{struct Node* cur2=head;int count=0;while(cur2!=cur->random){cur2=cur2->next;count++;}struct Node* copycur2=copyhead;while(count--){copycur2=copycur2->next;}copycur->random=copycur2;copycur=copycur->next;}cur=cur->next;}return copyhead;
}

解法二

我们可以不难看出上面的时间复杂度太大了,我们可以对上面的解法进行一点点的优化,我们采用指针数组先将每个random的地址给记录下来,最后在赋值这样也是可以的。但是仅仅只是优化了一点点。

解法三

想要真正的优化时间复杂度,那么我们必须要从思路开始下手了。

我们可以采用这样的思路:

首先这是我们的原来的链表

 我们可以在每一个结点的后面拷贝一个结点出来,如下图所示

最终形式如下图所示

 对于这个操作,其实是不难的

这部分的代码如下所示

 复制完成以后,我们接下来就要处理random了

最后一步就是,解开原链表 。

解开原来的链表,我们需要使用一个copyhead和copytail指针来管理copy链表,并且逐步解开解开

 

最终代码如下所示

/*** Definition for a Node.* struct Node {*     int val;*     struct Node *next;*     struct Node *random;* };*/struct Node* copyRandomList(struct Node* head) {//复制struct Node* cur=head; while(cur){struct Node* copy=(struct Node*)malloc(sizeof(struct Node));copy->val=cur->val;struct Node* next=cur->next;cur->next=copy;copy->next=next;cur=next;}//处理randomcur=head;while(cur){struct Node* copy=cur->next;if(cur->random==NULL){copy->random=NULL;}else{copy->random=cur->random->next;}cur=cur->next->next;}//解开两个链表cur=head;struct Node* copyhead=NULL;struct Node* copytail=NULL;while(cur){struct Node* copy=cur->next;struct Node* next=copy->next;if(copyhead==NULL){copyhead=copytail=copy;cur->next=next;}else{copytail->next=copy;copytail=copy;cur->next=next;}cur=next;}return copyhead;
}

本节内容到此为止

如果对你有帮助的话,不要忘记点赞加收藏哦!!!

相关文章:

【数据结构】第四站:单链表力扣题(二)

目录 一、链表的回文结构 二、相交链表 三、环形链表 四、环形链表Ⅱ 五、复制带随机指针的链表 一、链表的回文结构 题目描述&#xff1a;链表的回文结构_牛客题霸_牛客网 对于这道题&#xff0c;如果没有前面的一些题的基础&#xff0c;是非常难做的&#xff0c;我们的思…...

KafKa知识汇总

前言 汇总相关知识 Kafka快速实战与基本原理详解...

【RV1126】调试GT911,1024x600 7寸 MIPI 电容触摸屏

文章目录一、驱动注册失败二、触摸屏可以触摸&#xff0c;但是x轴数据反了三、可以触摸了&#xff0c;但是Y轴数据跳变&#xff0c;几乎只有一半的屏幕是可以正常滑动的三、汇顶触摸屏配置文件解析四、使用新的配置文件4.1 新配置解决问题4.2 测试触摸的方法在kernel增加frame …...

C的强符号/弱符号

首先上代码和结果&#xff1a; 代码&#xff1a; #include <stdio.h> int k; int k; int main() {printf("addr of k %p\n", &k);printf("value of k %d\n", k);return 0; }结果&#xff1a; addr of k 00408074 value of k 0问题&…...

AD/DA转换(XPT2046)

AD/DA介绍AD&#xff08;Analog to Digital&#xff09;&#xff1a;模拟-数字转换&#xff0c;将模拟信号转换为计算机可操作的数字信号DA&#xff08;Digital to Analog&#xff09;&#xff1a;数字-模拟转换&#xff0c;将计算机输出的数字信号转换为模拟信号AD/DA转换打开…...

乐观锁和悲观锁 面试题

Mysql的乐观锁和悲观锁 实现方式加锁时机常见的调用方式优势不足适用场景乐观锁开发自定义更新数据的时候sql语句中进行version的判断高并发容易出现不一致的问题高并发读&#xff0c;少写悲观锁Mysql内置查询数据的开始select * for update保证一致性低并发互联网高并发场景极…...

【Autoware规控】mpc_follower模型预测控制节点

文章目录1. 技术原理2. 代码实现1. 技术原理 MPC&#xff0c;即Model Predictive Control&#xff08;模型预测控制&#xff09;&#xff0c;是一种基于动态模型的控制算法。MPC算法通过建立系统的数学模型&#xff0c;根据当前状态和一定时间内的预测&#xff0c;优化未来的控…...

成果VR虚拟3D展厅让内容更丰富饱满

随着数字技术的不断发展和普及&#xff0c;数字化展厅成为了一种重要的展示形式。线上虚拟展厅作为数字化展示的一种新形式&#xff0c;采用虚拟现实技术&#xff0c;能够克服时空限制&#xff0c;打破传统展览业的展示模式&#xff0c;为用户提供更加丰富、立体、沉浸式的展览…...

【CE进阶】lua脚本使用

▒ 目录 ▒&#x1f6eb; 导读需求开发环境1️⃣ 脚本窗口Lua ScriptLua EngineAuto assemble2️⃣ 全局变量3️⃣ 进程当前打开的进程ID系统的进程列表系统的顶部窗口列表4️⃣ 线程5️⃣ 输入设备6️⃣ 屏幕7️⃣ 剪贴板&#x1f6ec; 文章小结&#x1f4d6; 参考资料&#x…...

【vue2】近期bug收集与整理02

⭐【前言】 在使用vue2构建页面时候&#xff0c;博主遇到的问题难点以及最终的解决方案。 &#x1f973;博主&#xff1a;初映CY的前说(前端领域) &#x1f918;本文核心&#xff1a;博主遇到的问题与解决思路 ⭐数据枚举文件的使用 同后端那边发送请求的时&#xff0c;请求返…...

2. 01背包问题

文章目录QuestionIdeasCodeQuestion 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi &#xff0c;价值是 wi 。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入…...

【Docker】CAdvisor+InfluxDB+Granfana容器监控

文章目录原生命令 docker stats容器监控3剑客CIGCAdvisorInfluxDBGranfanacompose容器编排&#xff0c;一套带走新建目录新建3件套组合的 docker-compose.yml检查配置&#xff0c;有问题才有输出 docker-compose config -q启动docker-compose文件 docker-compose up -d测试浏览…...

k8s 部署nginx 实现集群统一配置,自动更新nginx.conf配置文件 总结

k8s 部署nginx 实现集群统一配置&#xff0c;自动更新nginx.conf配置文件 总结 大纲 1 nginx镜像选择2 创建configmap保存nginx配置文件3 使用inotify监控配置文件变化4 Dockerfile创建5 调整镜像原地址使用阿里云6 创建deploy部署文件部署nginx7 测试使用nginx配置文件同步&…...

动态内存管理(上)——“C”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是动态内存管理噢&#xff0c;下面&#xff0c;让我们进入动态内存管理的世界吧 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 为什么存在动态内存分配 我们已…...

GPT-4发布,这类人才告急,大厂月薪10W+疯抢

ChatGPT最近彻底火出圈&#xff0c;各行各业都在争相报道&#xff0c;甚至连很多官媒都下场“跟风”。ChatGPT的瓜还没吃完&#xff0c;平地一声雷&#xff0c;GPT-4又重磅发布&#xff01; 很多小伙伴瑟瑟发抖&#xff1a;“AI会不会跟自己抢饭碗啊&#xff1f;” 关于“如何…...

MySQL数据库实现主主同步

前言 MySQL主主同步实际上是在主从同步的基础上将从数据库也提升成主数据库&#xff0c;让它们可以互相读写数据库&#xff0c;从数据库变成主数据库&#xff1b;主从相互授权连接&#xff0c;读取对方binlog日志并更新到本地数据库的过程,只要对方数据改变&#xff0c;自己就…...

JavaScript传参的6种方式

JavaScript传参的方式1. 传递基本类型参数2. 传递对象类型参数3. 使用解构赋值传递参数4. 使用展开运算符传递参数5. 使用可选参数6. 使用剩余参数JavaScript是一门非常灵活的语言&#xff0c;其参数传递方式也同样灵活。在本篇文章中&#xff0c;会详细介绍JavaScript中的参数…...

蓝桥之统计子矩阵

样例说明 满足条件的子矩阵一共有 19 , 包含: 大小为 11 的有 10 个。 大小为 12 的有 3 个。 大小为13 的有 2 个。 大小为 14 的有 1 个。 大小为 21 的有 3 个。 前缀和二维数组 前缀和暴力搜索 import java.util.*; public class Main{private static int ans0;pub…...

Java的基础面试题

一.java基础1.JDK和JRE有什么区别&#xff1f;JDK是java开发工具包&#xff0c;JRE是java运行时环境&#xff08;包括Java基础类库&#xff0c;java虚拟机&#xff09;2.和equals的区别是什么&#xff1f;比较的是两者的地址值&#xff0c;equals比较的是两者的内容是否一样3.两…...

J1939故障码诊断说明

1&#xff1a;1939整体协议说明 这里主要说明1939不同的协议&#xff0c;对应不同的网络分层 注意了&#xff0c;这里只进行文档解析说明&#xff0c;具体查看去搜素协议的关键字进行理解 2&#xff1a;DMx和FMI 说明 想知道每个代号的具体含义&#xff0c;可以去 saeJ1939…...

XCPC第十三站,贪心问题

一.区间选点 我们采取这样的策略来选点&#xff1a;step&#xff08;1&#xff09;将区间按照右端点的大小从小到大排序&#xff1b;step&#xff08;2&#xff09;从前往后依次枚举每个区间&#xff0c;如果当前区间中已经包含点&#xff0c;直接pass&#xff0c;否则选当前区…...

一文让你吃透 Vue3中的组件间通讯 【一篇通】

文章目录前情回顾前言1. 父组件 > 子组件通讯传递2. 子组件 > 父组件通讯传递3. 爷孙组件&#xff0c;后代组件通讯数据总结前情回顾 在本专栏前一章节中&#xff0c;我为大家带来了 Vue3 新特性变化上手指南 的归纳梳理&#xff0c;主要介绍了 Vue3 的 Proxy 响应式原理…...

EVE遭遇大规模DDOS攻击,玩家和官方都傻眼了

如果你恰好是一名《星战前夜》&#xff08;EVE&#xff09;的国际服玩家&#xff08;虽然这个几率很小&#xff09;&#xff0c;又恰好因为疫情一直待在家里&#xff0c;那你就真是倒霉透顶了。因为从1月底开始&#xff0c;EVE的服务器就一直受到大规模的DDOS攻击&#xff0c;而…...

【数据结构】二叉树及相关习题详解

新年新气象! 祝大家兔年 财源滚滚! 万事胜意! 文章目录前言1. 树的一些基础概念1.1 树的一些基本概念1.2 树的一些重要概念2. 二叉树的一些基本概念2.1 二叉树的结构2.2 两种特殊的二叉树3. 二叉树的性质4. 二叉树的存储5. 二叉树的基本操作5.1 构造一棵二叉树5.2 二叉树的遍历…...

锂电池充电的同时也能放电吗?

大家应该都有这样经历&#xff0c;我们的手机在充电的同时也能边使用&#xff0c;有的同学就会说了&#xff0c;这是因为手机电池在充电的同时也在放电。如果这样想我们可能就把锂电池类比了一个蓄水池&#xff0c;以为它在进水的同时也能出水&#xff0c;其实这个比喻是错误的…...

通信工程考研英语复试专有名词翻译

中文英文频分多址Frequency Division Multiple Access码分多址Code Division Multiple Access时分多址Time Division Multiple Access移动通信mobile communication人工智能artificial intelligence水声通信Middle-Range Uwa Communication正交频分复用Orthogonal frequency di…...

注意力机制(四):多头注意力

专栏&#xff1a;神经网络复现目录 注意力机制 注意力机制&#xff08;Attention Mechanism&#xff09;是一种人工智能技术&#xff0c;它可以让神经网络在处理序列数据时&#xff0c;专注于关键信息的部分&#xff0c;同时忽略不重要的部分。在自然语言处理、计算机视觉、语…...

【2023Unity游戏开发教程】零基础带你从小白到超神19——射线检测

文章目录 射线检测从某点发射一条射线从摄像机发射一条射线射线检测 游戏中的红外线,默认肉眼是看不到的,从某个初始点开始,沿着特定的方向发射一条不可见且无限长的射线,通过此射线检测是否有任何模型添加了Collider碰撞器组件。一旦检测到碰撞,停止射线继续发射。 碰撞检…...

内存泄漏和内存溢出的区别

参考答案 内存溢出(out of memory)&#xff1a;指程序在申请内存时&#xff0c;没有足够的内存空间供其使用&#xff0c;出现 out of memory。内存泄露(memory leak)&#xff1a;指程序在申请内存后&#xff0c;无法释放已申请的内存空间&#xff0c;内存泄露堆积会导致内存被…...

文本三剑客之sed编辑器

文本三剑客&#xff1a;都是按行读取后处理。 grep 过滤行内容。awk 过滤字段。sed 过滤行内容&#xff1b;修改行内容。sed编辑器 sed是一种流编辑器&#xff0c;流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。 sed编辑器可以根据命令来处理数据流中…...

柳州市建设中心网站/c++线上培训机构哪个好

【秋游】 五颜六色花朵色&#xff0c;万紫千红秋天景。 谁言秋景只金黄&#xff0c;却道人间已换天。...

榆林免费做网站/电商运营自学全套教程

程序组装代码存在吗? 每个程序是代码组成的,固定的程序可能是固定的代码,当其组装完成后,就可以执行这段程序. 怪不得代码搬运工这样的字眼会存在,那编程的意义何在? 字母A联合字母B形成了程序AB,但A与B已经是存在的A与B.既然已经存在,并且可按规律或规则规范去组织进行使用.…...

太原网站建设培训学校/线上运营推广

网页设计中计算机图像处理技术的运用(共2642字)网页设计中计算机图像处理技术的运用(共2642字)随着计算机技术的不断发展&#xff0c;社会对网页设计的质量要求越来越高&#xff0c;如何将网页内容所要表达的内容形象的展现在浏览者面前是计算机图像处理技术的重要任务。在网页…...

宁夏信用建设官方网站/最新百度新闻

sp_executesql 可能用 exec sp_executesql sqltext,paramstring,urlM_ID output 来得到动态执行中返回值&#xff0c;sqltext的长度可能超过了4000字符&#xff0c;可以使用nvarchar(max)解决&#xff0c;类似于&#xff1a; declare request1 nvarchar(4000) declare request2…...

django 做网站 原理/seo实战培训

系统安装时候使用的默认分区&#xff0c;根分区只分了50G&#xff0c;使用的是LVM 想把home分区分出来660G给根分区 先查了点资料开搞 由于xfs分区只支持增大&#xff0c;不支持缩小&#xff0c;所以home目前是xfs格式无法进行缩小操作&#xff0c;该怎么办&#xff1f; 想到了…...

wordpress 微信主体/深圳网站优化排名

在activiti中框架中。默认支持mysql/oracle/sqlserver等数据库&#xff0c;下面参考activiti的做法封装一套jdbc操作。 1、针对一张表的操作者&#xff0c;系统表的操作有以下几种 /*** <pre>* 针对一张表的操作者&#xff0c;系统表的操作有以下几种* 针对表本身的&am…...