数据结构——单链表OJ题(下)

目录

一、链表的回文结构

思路一:数组法

(1)注意

(2)解题

思路二:反转链表法

(1) 注意

(2)解题

二、相交链表

(1)思路:快慢指针

(2)注意

(3)解题

 三、环形链表1

(1)思路:快慢指针

(2)解释

(3)注意

(4)解题

①快指针走两步

② 快指针走三步

四、环形链表2

(1)思路:快慢指针

(2)解释

(3)注意

(4)解题

五、随机链表的复制

(1)思路

(2)解题

六、写在最后 


一、链表的回文结构

思路一:数组法

将链表中结点的数据存储在数组中,创建两个指针分别从左右两边遍历并比较,如果左右对称则说明是回文结构。

(1)注意

①为什么要创建数组存储数据?因为链表的结点不是连续的,不能进行逆向访问;

②从左右两端进行遍历时,需满足left<right的条件;

③该方法只适用于链表长度小于等于900的条件下,因为数组的长度最大为900。

(2)解题

typedef struct ListNode ListNode;
bool chkPalindrome(ListNode* A) {//创建数组存储数据int arr[900] = {0};//数据的个数为iint i = 0;ListNode* pcur = A;//遍历链表,将数据存储在数组中while(pcur){arr[i++] = pcur->val;pcur = pcur->next;}int left = 0;int right = i - 1;while(left < right){//若有不相等,说明不是回文结构if(arr[left] != arr[right]){return false;}left++;right--;}//跳出循环,说明left和right指向的数据一直相等,即回文结构return true;}

思路二:反转链表法

使用快慢指针法找到原链表的中间结点,将中间结点之后的链表进行反转,最后将原链表的前半段与新链表存储的数据进行比较。

(1) 注意

①寻找中间结点和反转链表在上节已练习,可将它们封装成两个函数;

②由于原链表的长度大于新链表(反转后的),因此循环结束的判定条件是p2==NULL。

(2)解题

class PalindromeList {//寻找中间结点的函数ListNode* midNode(ListNode* head){ListNode* fast = head;ListNode* slow = head;while(fast && fast->next){fast = fast->next->next;slow = slow->next;}return slow;}//将链表进行反转的函数ListNode* reverse(ListNode* head){ListNode* n1, * n2 , *n3;n1 = NULL;n2 = head;n3 = head->next;while(n2){n2->next = n1;n1 = n2;n2 = n3;if(n3){n3 = n3->next;}}return n1;}
public:bool chkPalindrome(ListNode* A) {//原链表的中间结点ListNode* mid = midNode(A);//将中间结点之后的链表进行反转ListNode* p2 = reverse(mid);ListNode* p1 = A;//遍历两个链表的值,比较是否相等while(p2){//存在不相等的,说明不是回文结构if(p1->val != p2->val){return false;}p1 = p1->next;p2 = p2->next;}//跳出循环,说明left和right指向的数据都相等,即为回文结构return true;}
};

二、相交链表

(1)思路:快慢指针

首先找到两个链表长度的差值k,创建两个指针指向头结点,快指针先走k步,接着快慢指针一起走,若快慢指针指向同一个结点,则说明该结点为相交结点。

(2)注意

①计算差值时无法确定两个长度谁大谁小,可使用abs()绝对值函数;

②通过比较两个长度的大小来确定快指针指向哪个链表的头结点;

③判断快慢指针指向的结点是否相同,而非结点指向的数据!!

(3)解题

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{//计算两个链表的长度int len1 = 0;int len2 = 0;ListNode* pcur = headA;while(pcur){pcur = pcur->next;len1++;}pcur = headB;while(pcur){pcur = pcur->next;len2++;}//两个链表长度的差值kint k = abs(len1 - len2);//快指针指向长链表的头结点ListNode* fast = headA;ListNode* slow = headB;if(len1 < len2){fast = headB;slow = headA;}//快指针先走k步while(k--){fast = fast->next;}//比较两个指针指向的结点是否相同while(fast && slow){if(fast == slow){return fast;}fast = fast->next;slow = slow->next;}return NULL;
}

 三、环形链表1

(1)思路:快慢指针

创建快慢指针并指向头结点,快指针一次经过两个结点,慢指针一次经过一个结点,若最终快指针与慢指针相遇,则说明该链表是环形链表。

(2)解释

①为什么在起点相同的情况下,快指针走两步,慢指针走一步,两者可以相遇,会不会遇不上?

假设此时fast进入环,slow走完入环前的距离准备入环,此时它们之间的距离为N。在接下来的追逐中,它们每追击(变换位置)一次,两者之间的距离缩小一步,直至相遇。(参考下图理解)

 

②如果慢指针一次走一步,快指针一次走3、4、5...n步,快慢指针还能再相遇吗?

可以!以快指针一次走3步为例:

slow入环后,slow和fast在环内进行追逐,假设两者之间的距离为N,那么在之后的过程中,每追逐一次两者之间的距离就缩小两步。

若N为偶数,最终距离可缩小为0,即相遇;若N为奇数,假设环的长度为C,会出现套圈情况(即slow走在fast前面),此时两者之间的长度为C-1。

此时需要讨论C-1是奇数还是偶数,若C-1为偶数,则可以相遇。若C-1为奇数,两者还会错过,继续套圈,那么fast和slow还会再相遇吗?

假设slow走完入环前的距离L,刚准备入环;fast在环里走了x圈,且此时fast和slow之间的距离为N,那么两者走过的长度分别为:slow : L     fast : L + xC + (C - N)。又因为fast的速度是slow的3倍,因此3L =  L + xC + (C - N),化简得:2L = (x + 1)C - N

上述条件中:N为奇数,C为偶数。因为:偶数= 偶数-偶数,偶数=奇数-奇数。那么(x+1)C为奇数时,会相遇。因此,如果慢指针一次走一步,快指针一次走3步,快慢指针还能再相遇。

同理可得其它步数的情况下也可相遇。

(3)注意

①循环结束的判定条件是fast && fast->next:若fast为空则说明不是环形链表;

②不能写成fast->next && fast,要先判断fast,因为如果fast为空,就不能取next;

③虽然证明了快指针不论走多少步都可以满足在带环链表中相遇,但是在编写代码的时候会有额外的步骤引入,涉及到快慢指针的算法题中通常习惯使用慢指针走一步、快指针走两步的方式。

(4)解题

①快指针走两步
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) 
{ListNode* fast = head;ListNode* slow = head;while(fast && fast->next){fast = fast->next->next;slow = slow->next;if(fast == slow){return true;}}return false;
}
② 快指针走三步
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) 
{ListNode* fast = head;ListNode* slow = head;while(fast && fast->next){slow = slow->next;//快指针一次走三步int n = 3;while(n--){if(fast->next){fast = fast->next;}else {return false;}}if(fast == slow){return true;}}return false;
}

四、环形链表2

(1)思路:快慢指针

创建两个指针,一个从链表的头结点开始遍历链表,另一个从快慢指针的(判断是否为环形链表的)相遇点开始绕环运行,两个指针都是一次走一步,最终会在入口点的位置相遇。

(2)解释

①为什么相遇点和头结点到入环结点的距离是相等的?

假设环的长度为R,入环之前的距离为L,入环节点到相遇点的距离为X,那么相遇点到入环结点之间的距离为R-X。

在判环时(此时在相遇点),快慢指针走的路程为:slow : L+X     fast :L+nR+X(其中n≥1)。

由于判环时,快指针一次走两步,慢指针一次走一步,则快指针的路程时慢指针的两倍。且慢指针入环之后,快指针一定会在一圈之内追上慢指针(因为慢指针入环之后,两者之间的距离最大为环的长度,而每追击一次,两者之间的距离缩短一步,因此在一圈之内,快指针一定能追上慢指针)。

那么:2*(L+X)= L+nR+X,化简为:L = nR - X,即L = (n -1)R+(R-X)。在极端情况下:假设n=1,则:L=R-X,即头结点到和相遇点到入环结点之间的距离相等。

(3)注意

①fast && fast->next位置的注意事项同上。

(4)解题

typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) 
{ListNode *fast = head;ListNode *slow = head;while(fast && fast->next){//fast一次走两步,slow一次走一步fast = fast->next->next;slow = slow->next;if(fast == slow){ListNode* pcur = head;//判断两者何时相遇while(pcur != slow){pcur = pcur->next;slow = slow->next;}return slow;}}//链表不带环return NULL;
}

五、随机链表的复制

 

(1)思路

在原链表的基础上继续复制链表,置random指针(copy->random = pcur->random->next),最后将复制链表和原链表断开,得到复制链表。

(2)解题

typedef struct Node Node;
Node* buyNode(int x) {Node* newnode = (Node*)malloc(sizeof(Node));newnode->val = x;newnode->next = newnode->random = NULL;return newnode;
}
void AddNode(Node* phead) {Node* pcur = phead;while (pcur) {// 存储pcur的下一个结点Node* Next = pcur->next;// 创建新结点,尾插到pcurNode* newnode = buyNode(pcur->val);pcur->next = newnode;newnode->next = Next;pcur = Next;}
}
struct Node* copyRandomList(struct Node* head) {if(head == NULL){return NULL;}// 1.在原链表上复制结点AddNode(head);// 2.置randomNode* pcur = head;while (pcur) {Node* copy = pcur->next;if (pcur->random != NULL) {copy->random = pcur->random->next;}pcur = copy->next;}// 3.断开链表pcur = head;Node *newHead, *newTail;newHead = newTail = pcur->next;while (pcur->next->next) {pcur = pcur->next->next;newTail->next = pcur->next;newTail = newTail->next;}return newHead;
}

六、写在最后 

 链表既然包括单链表,就还有其他种类啦~

敬请期待“双向链表”~

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

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

相关文章

优化算法:1.遗传算法(GA)及Python实现

一、定义 遗传算法就像是在模拟“优胜劣汰”的进化过程&#xff0c;通过选择最优秀的个体&#xff0c;交配产生下一代&#xff0c;并引入一定的变异&#xff0c;逐步优化解决问题。 二、具体步骤 初始化种群(Initialization)&#xff1a; 假设你要找到一个迷宫的最佳出口路径。…

CTF-NSSCTF[GKCTF 2021]

[GKCTF 2021]easycms 考察&#xff1a; 用扫描工具扫描目录&#xff0c;扫描到后台登录界面/admin.php 题目提示了密码是五位弱口令&#xff0c;试了试弱口令admin和12345直接成功了 任意文件下载 点击设计-->主题然后随便选择一个主题&#xff0c;点击自定义&#xff0…

故障诊断 | 基于Transformer故障诊断分类预测(Matlab)

文章目录 预测效果文章概述程序设计参考资料预测效果 文章概述 Transformer故障诊断/分类预测 | 基于Transformer故障诊断分类预测(Matlab) Transformer 模型本质上都是预训练语言模型,大都采用自监督学习 (Self-supervised learning) 的方式在大量生语料上进行训练,也就是…

CTF之网站被黑

简单看一下网页和源码没发现什么明显漏洞 那就扫描一下目录 发现了/shell.php文件&#xff0c;访问一下&#xff0c;发现是一个后台管理登录页面 别无他法只能爆破喽&#xff0c;爆破后发现密码是hack flag{25891d9e9d377f006eda3ca7d4c34c4d}

@JSONField(format = “yyyyMMddHH“)的作用和使用

JySellerItqrdDataDO对象中的字段为&#xff1a; private Date crdat; 2.数据库中的相应字段为&#xff1a; crdat datetime DEFAULT NULL COMMENT 创建时间,2. 打印出的结果为&#xff1a; “crdat”:“2024072718” 年月日时分秒 3. 可以调整format的格式 4. 这样就把Date类…

RedHat8安装Oracle19C

RedHat8安装Oracle19C 1、 更新yum源 更新yum源为阿里云镜像源&#xff1a; # 进入源目录 cd /etc/yum.repos.d/ # 删除 redhat 默认源 rm redhat.repo # 下载阿里云的centos7源 curl -O http://mirrors.aliyun.com/repo/Centos-8.repo # 替换 Centos-8.repo 中的 $releasev…

初学Mybatis之 Lombok 篇

idea 安装 Lombok 插件&#xff1a; File->Settings->Plugins->搜索 lombok 下载 在项目中导入 lombok 的 jar 包&#xff1a; <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.…

C语言程序设计之数学函数篇

程序设计之数学函数 问题1_1代码1_1结果1_1 问题1_2代码1_2结果1 _2 问题1_3代码1_3结果1_3 问题1_1 函数 f u n fun fun 的功能是计算&#xff1a; s ln ⁡ ( 1 ) ln ⁡ ( 2 ) ln ⁡ ( 3 ) ⋯ ln ⁡ ( n ) s\sqrt{\ln(1)\ \ \ln(2)\ \ \ln(3)\ \ \cdots \ \ \ln(n)\ } …

ReentrantReadWriteLock详解

目录 ReentrantReadWriteLock详解1、ReentrantReadWriteLock简介2、ReentrantReadWriteLock类继承结构和类属性3、ReentrantReadWriteLock的读写锁原理分析4、ReentrantReadWriteLock.WriteLock类的核心方法详解非公平写锁的获取非公平写锁的释放公平写锁的获取公平写锁的释放 …

win11查找句柄泄露

1.打开任务管理器&#xff0c;不会的网上搜 2.选择详细信息 3.注意了 比较坑的一点 win11上详细信息不会默认显示句柄数。&#xff08;默认没有句柄那一列&#xff0c;妈的花了我好长时间找&#xff09; 右键&#xff0c;点击选择列 选择句柄 下面的列表里就能看到进程使用…

显著提升“视触觉传感器耐磨性”的贴金工艺,在植物和古生物化石检测上取得良好的识别效果

贴金&#xff0c;一种古老的技艺&#xff0c;是中华民族民间传统工艺的瑰宝&#xff01;金箔和贴金工艺的结合让朴实无华的工艺品重获新生。正如《天工开物》所述&#xff1a;“凡色至于金&#xff0c;为人间华美贵重&#xff0c;故人工成箔而后施之”。这项古老技艺如今可用于…

PyCharm 常用 的插件

Material Theme UI Lite&#xff1a;‌提供多种不同的页面风格&#xff0c;‌为PyCharm界面增添个性化元素。‌Chinese (Simplified) Language Pack&#xff1a;‌为中文用户提供简体中文的界面、‌菜单、‌提示信息&#xff0c;‌提升使用体验。‌Tabnine&#xff1a;‌基于人…

Harmony学习(三)

1.模版字符串 let name:string 模版字符串 let age:number 18 console.log(字符串:,${name}和${age})2.字符串和数字互相转换 //字符串转数字 let str1:string 1.1 console.log(转换,Number(str1)) //output: 1.1 console.log(转换,parseInt(str1)) //output: 1 conso…

3.k8s:服务发布:service,ingress;配置管理:configMap,secret,热更新;持久化存储:volumes,nfs,pv,pvc

目录​​​​​​​ 一、服务发布 1.service &#xff08;1&#xff09;service和pod之间的关系 &#xff08;2&#xff09; service内部服务创建访问 &#xff08;3&#xff09;service访问外部服务 &#xff08;4&#xff09;基于域名访问外部 &#xff08;5&#xff…

Java中的优先级队列(PriorityQueue)(如果想知道Java中有关优先级队列的知识点,那么只看这一篇就足够了!)

前言&#xff1a;优先级队列&#xff08;Priority Queue&#xff09;是一种抽象数据类型&#xff0c;其中每个元素都关联有一个优先级&#xff0c;元素按照优先级顺序进行处理。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 …

足浴行业押金原路退回怎么开通?

一手机版和电脑版差别 手机版押金管理的优点&#xff1a; 1. 便携性&#xff1a;管理人员可以随时随地通过手机查看和处理押金相关事务&#xff0c;不受地点限制。例如&#xff0c;当不在店内时&#xff0c;仍能及时了解押金的收支情况&#xff0c;对突发问题进行处理。 2. 实…

基于微信小程序的校园二手交易平台/Java的二手交易网站/基于Javaweb校园二手商品交易系统(附源码)

摘 要 使用校园二手交易平台管理校园二手物品交易&#xff0c;不仅实现了智能化管理&#xff0c;还提高了管理员的管理效率&#xff0c;用户查询的功能也需要校园二手交易平台来提供。 设计校园二手交易平台是毕设的目标&#xff0c;校园二手交易平台是一个不断创新的系统&…

【通信模块】简单玩转WiFi模块(ESP32、ESP8266)

笔者学习太极创客的学习笔记&#xff0c;链接如下&#xff1a;www.taichimaker.com 前期准备 电脑端口 固件烧录 WIFI到网页 对应七层网络协议 WIFI工作模式&#xff08;链路层&#xff09; 接入点模式、无线中断模式、混合模式 IP协议&#xff08;网络层&#xff09; 子网…

Kafka知识总结(选举机制+控制器+幂等性)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 选举机制 控制器&#xff08;Broker&#xff09;选举 控制器就是…

springboot使用Gateway做网关并且配置全局拦截器

一、为什么要用网关 统一入口&#xff1a; 作用&#xff1a;作为所有客户端请求的统一入口。说明&#xff1a;所有客户端请求都通过网关进行路由&#xff0c;网关负责将请求转发到后端的微服务 路由转发&#xff1a; 作用&#xff1a;根据请求的URL、方法等信息将请求路由到…