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

目录

前言

题目一:链表的中间节点

思路

分析

题解

 题目二:链表中倒数第k个结点

思路

分析

 题解

题目三:合并两个有序链表

思路

分析

题解

 方法二

题解

 题目四:链表的回文结构

思路

分析

题解

总结


前言

        今天我将开启一个新的专栏,数据结构与算法刷题训练营,题目从基础简单题目开始逐步进阶,以便于初学者巩固和运用所学的知识。


题目一:链表的中间节点

 题目描述:

 示例与提示:

 题目链接

链表的中间节点icon-default.png?t=N6B9https://leetcode.cn/problems/middle-of-the-linked-list/description/

 思路

        题目中的链表属于单链表,我们要怎么计算中间节点呢?先遍历一遍链表统计链表节点个数,然后计算出中间节点,再遍历到需要返回的节点。这或许是大多数人能想到的方法。但是这种方法效率太低。今天我向大家介绍一种新的做题思路,这种方法在其他题目中也是适用。

快慢指针法:

        我们可以创建两个指针,一个快指针一次走两步,一个慢指针一次走一步。当快指针走到尾时,返回慢指针就是中间节点。

分析

情况一:

节点为奇数个。

         假设节点有5个,那需要返回的节点就是第3个节点。初始时,两指针都指向第一个节点,慢指针一次走一步,快指针一次走两步。执行一次情况如上图。当快指针走到最后一个节点时就要结束如下图:

 情况二:

节点为偶数个。

         这是已经执行两次后的状态,接下来fast指针继续走:

         fast指向NULL,而slow指向要返回的节点。

题解

         了解完整体思路,我们依据分析中的情况进行编写代码:

struct ListNode* middleNode(struct ListNode* head)
{struct ListNode* fast=head,*slow=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}return slow;}

 

 题目二:链表中倒数第k个结点

 题目描述:

 题目链接

倒数第k个节点icon-default.png?t=N6B9https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

思路

         这道题目依然可以使用快慢指针的方法来寻找倒数第k个节点。先让快指针走k步,然后让两指针同时向后移动,知道快指针遍历完链表结束。

分析

         初始情况下,两指针都指向第一个节点,先让fast指针走k步:

        我们假设要找倒数第3个节点,fast走3步就指向了第四个节点。

         然后两指针开始同时移动:

         当fast指针指向NULL时就结束,此时slow指向的就是倒数第k个节点。

 题解

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

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {struct ListNode* fast=pListHead,*slow=pListHead;for(int i=0;i<k;i++){if(fast==NULL){return NULL;}fast=fast->next;}while(fast){fast=fast->next;slow=slow->next;}return slow;
}

        在代码实现时要注意特殊情况,如果链表为NULL或者k大于链表长度,传进来就要进行特殊处理。

题目三:合并两个有序链表

 题目描述:

 示例:

 题目链接:

合并两个有序链表icon-default.png?t=N6B9https://leetcode.cn/problems/merge-two-sorted-lists/description/

思路

        题目中给的是升序数组,解题思路就是比较链表元素,取小的进行尾插。思路较为简单。

分析

 接下来我们对整体规划进行分析假设初始时:

         把一个链表的元素插入到另一个链表这样操作太麻烦,所以我们可以重新创建一个头指针,将两个链表上的节点插入到新的链表中,创建新链表时,初始化头和尾都为NULL。

 

         然后进行比较,第一步两个大小相同,任取一个插入:

 

         然后再拿着list2中的第一个节点与list1节点进行比较,插入:

         以此类推不断进行比较尾插。

 

        结束条件就是一个链表为NULL结束 

 

         最后将剩余节点的链表尾插到新链表中,返回新链表的头。

题解

        理解了思路就根据分析的内容进行编写代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if(list1==NULL)                //考虑原链表中有空链表的情况。return list2;if(list2==NULL)return list1;struct ListNode* head=NULL,*tail=NULL;while(list1&&list2){if(list1->val > list2->val)//比较大小取小的尾插{if(head==NULL)         //考虑特殊情况新建链表为NULL时进行特殊处理{tail=head=list2;}else                   //尾插{tail->next=list2;tail=tail->next;}list2=list2->next;    //尾插后继续向后}else{if(head==NULL){tail=head=list1;}else{tail->next=list1;tail=tail->next;}list1=list1->next;}}if(list2==NULL)            //一个链表为NULL时将另一个链表剩余的节点尾插到新链表。tail->next=list1;elsetail->next=list2;return head;
}

 虽然思路非常简单,但是代码实现却很不容易,需要很多要考虑的特殊情况。

 

 方法二

        和思路一相同,也是比较大小,将小的尾插到新的链表。但是可以使用带头结点的链表,这样再插入时就不需要考虑新链表为NULL时的情况,进行特殊处理。可以更好的简化代码。

题解

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if(list1==NULL)return list2;if(list2==NULL)return list1;struct ListNode* head=NULL,*tail=NULL;head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));while(list1&&list2){if(list1->val > list2->val){tail->next=list2;tail=tail->next;list2=list2->next;}else{tail->next=list1;tail=tail->next;list1=list1->next;}}if(list2==NULL)tail->next=list1;elsetail->next=list2;struct ListNode* del=head;head=head->next;free(del);return head;
}

         注意:原链表中不带头节点,返回时不能返回头节点,需要将头节点释放掉,返回头节点的下一个节点。

 

 题目四:链表的回文结构

题目描述:

 题目链接:

链表的回文结构icon-default.png?t=N6B9https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking

思路

        有人可能会想,这不很简单吗?把这个链表反转一下,再和原链表数据依次比较不就解决了,但是这里注意题目要求。

        题目要求时间复杂度为O(N),空间复杂度为O(1),上述思路需要将原链表复制一份后才可以与逆置是链表进行比较,空间复杂度为O(N)。

        这道题的思路是这样的,可以先找到链表的中间节点,然后从中间节点开始,对后部分的链表进行逆置,然后从中间开始与开头的节点对比,看两个值是否相同。

分析

 情况一:

         节点为偶数个,把后半部分节点逆置,然后依次比较,这里注意其实前半部分的2节点的next这时依然指向的是后半部分的2,后半部分的2节点的next指向NULL。如下图:

 逆置之后,返回的是后半部分1节点的地址,然后进行遍历,直到为NULL结束。

情况二:

        节点数量为奇数个

 实际情况和上述一样:

         但这里在比较的时候就要注意一下3节点,这里不需要把前半部分2节点的next置为NULL,当遍历到最后时,都遍历到了3节点一定是相同的

题解

        当然这些逆置、找中间节点的接口我们已经写过了,可以CV一下前边的代码,这样写代码还是很舒服的Ctrl+C、Ctrl+V

        当然借此我再介绍一种新的逆置链表的方法,我们可以使用头插来实现链表逆置。将原链表的节点依次头插到新的节点,这样就轻松实现了逆置。

代码如下:

struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* cur=head;struct ListNode* newhead=NULL;while(cur){struct ListNode* next=cur->next;//头插cur->next=newhead;newhead=cur;cur=next;}return newhead;
}

 整体题解:

class PalindromeList {
public:
struct ListNode* reverseList(struct ListNode* head)
{struct ListNode* cur=head;struct ListNode* newhead=NULL;while(cur){struct ListNode* next=cur->next;cur->next=newhead;newhead=cur;cur=next;}return newhead;
}struct ListNode* middleNode(struct ListNode* head)
{struct ListNode* fast=head,*slow=head;while(fast && fast->next){slow=slow->next;fast=fast->next->next;}return slow;
}bool chkPalindrome(ListNode* A) {struct ListNode* mid=middleNode(A);//中间节点struct ListNode* rmid=reverseList(mid);//反转后的中间节点while(A && rmid)    {if(A->val!=rmid->val){return false;}else{rmid=rmid->next;A=A->next;}}return true;}
};

 


 

总结

        好的本期内容到此结束,后续我将会分享更多数据结构相关的题目,通过画图逐步分析,来帮助大家刷题,这些题目建议大家先做一遍,然后看思路与分析,一定要动手敲一敲代码。最后,感谢阅读!

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

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

相关文章

2023华数杯C题总结

前言 对这次比赛中遇到的问题和卡住的思路进行复盘&#xff0c;整理相关心得&#xff0c;供以后比赛参考 &#x1f9e1;1.认识数据类型&#x1f9e1; 连续变量&#xff1a;母亲年龄、妊娠时间、CBTS、EPDS、HADS、整晚睡醒时间、婴儿年龄 无序分类变量&#xff1a;婚姻状态、…

Gpt微信小程序搭建的前后端流程 - 前端小程序部分-2.确定交互所需的后端API(二)

Gpt微信小程序搭建的前后端流程 - 前端小程序部分-2.确定交互所需的后端API(二) 参考微信小程序-小柠AI智能聊天&#xff0c;可自行先体验。 根据上一节的小程序静态页面设计&#xff0c;需要从后端获取数据的主要4个点&#xff1a; 登录流程&#xff1b;获取今日已提问次数&a…

Unity制作护盾——2、力场冲击波护盾

Unity制作力场护盾 大家好&#xff0c;我是阿赵。   继续做护盾&#xff0c;这一期做一个力场冲击波护盾。 一、效果展示 主要的效果并不是这个球&#xff0c;而是护盾在被攻击的时候&#xff0c;会出现一个扩散的冲击波。比如上图在右边出现了冲击波 如果在左边被攻击&am…

MongoDB 6.0.8 安装配置

一、前言 MongoDB是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。在高负载的情况下&#xff0c;添加更多的节点&#xff0c;可以保证服务器性能。 MongoDB 将数据存储为一个文档&#xff0c;数据结构由键值(key>value…

[分享]STM32G070 串口 乱码 解决方法

硬件 NUCLEO-G070RB 工具 cubemx 解决方法 7bit 改为 8bit printf 配置方法 添加头文件 #include <stdio.h> 添加重定向代码 #ifdef __GNUC__#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)#else#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)#endi…

卷积神经网络实现MNIST手写数字识别 - P1

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营-第P1周&#xff1a;实现mnist手写数字识别&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同…

SPM(Swift Package Manager)开发及常见事项

SPM怎么使用的不再赘述&#xff0c;其优点是Cocoapods这样的远古产物难以望其项背的&#xff0c;而且最重要的是可二进制化、对xcproj项目无侵入&#xff0c;除了网络之外简直就是为团队开发的项目库依赖最好的管理工具&#xff0c;是时候抛弃繁杂低下的cocoapods了。 一&…

C语言:打开调用堆栈

第一步&#xff1a;打断点 第二步&#xff1a;FnF5 第三步&#xff1a;按如图找到调用堆栈

使用Flask.Request的方法和属性,获取get和post请求参数(二)

1、Flask中的request 在Python发送Post、Get等请求时&#xff0c;我们使用到requests库。Flask中有一个request库&#xff0c;有其特有的一些方法和属性&#xff0c;注意跟requests不是同一个。 2、Post请求&#xff1a;request.get_data() 用于服务端获取客户端请求数据。注…

积累常见的有针对性的python面试题---python面试题001

1.考点列表的.remove方法的参数是传入的对应的元素的值,而不是下标 然后再看remove这里,注意这个是,删除写的那个值,比如这里写3,就是删除3, 而不是下标. remove不是下标删除,而是内容删除. 2.元组操作,元组不支持修改,某个下标的内容 可以问他如何修改元组的某个元素 3.…

【MMU】认识 MMU 及内存映射的流程

MMU&#xff08;Memory Manager Unit&#xff09;&#xff0c;是内存管理单元&#xff0c;负责将虚拟地址转换成物理地址。除此之外&#xff0c;MMU 实现了内存保护&#xff0c;进程无法直接访问物理内存&#xff0c;防止内存数据被随意篡改。 目录 一、内存管理体系结构 1、…

idea打开多个项目需要开多个窗口(恢复询问弹窗)

【版权所有&#xff0c;文章允许转载&#xff0c;但须以链接方式注明源地址&#xff0c;否则追究法律责任】【创作不易&#xff0c;点个赞就是对我最大的支持】 前言 仅作为学习笔记&#xff0c;供大家参考 总结的不错的话&#xff0c;记得点赞收藏关注哦&#xff01; 使用…

【TypeScript】中定义与使用 Class 类的解读理解

目录 类的概念类的继承 &#xff1a;类的存取器&#xff1a;类的静态方法与静态属性&#xff1a;类的修饰符&#xff1a;参数属性&#xff1a;抽象类&#xff1a;类的类型: 总结&#xff1a; 类的概念 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JavaScript 中的…

一起学SF框架系列7.1-spring-AOP-基础知识

AOP(Aspect-oriented Programming-面向切面编程&#xff09;是一种编程模式&#xff0c;是对OOP(Object-oriented Programming-面向对象编程&#xff09;一种有益补充。在OOP中&#xff0c;万事万物都是独立的对象&#xff0c;对象相互耦合关系是基于业务进行的&#xff1b;但在…

MySQL之深入InnoDB存储引擎——Undo页

文章目录 一、UNDO日志格式1、INSERT操作对应的UNDO日志2、DELETE操作对应的undo日志3、UPDATE操作对应的undo日志1&#xff09;不更新主键2&#xff09;更新主键的操作 3、增删改操作对二级索引的影响 二、UNDO页三、UNDO页面链表四、undo日志具体写入过程五、回滚段1、回滚段…

C语言系列之原码、反码和补码

一.欢迎来到我的酒馆 讨论c语言中&#xff0c;原码、反码、补码。 目录 一.欢迎来到我的酒馆二.原码 二.原码 2.1在计算机中&#xff0c;所有数据都是以二进制存储的&#xff0c;但不是直接存储二进制数&#xff0c;而是存储二进制的补码。原码很好理解&#xff0c;就是对应的…

SQL Server数据库如何添加Oracle链接服务器(Windows系统)

SQL Server数据库如何添加Oracle链接服务器 一、在添加访问Oracle的组件1.1 下载Oracle的组件 Oracle Provider for OLE DB1.2 注册该组件1.2.1 下载的压缩包解压位置1.2.2 接着用管理员运行Cmd 此处一定要用管理员运行&#xff0c;否则会报错 二、配置环境变量三、 重启SQL Se…

IDEA开启并配置services窗口

一、选择view -> Tool Windows -> Services 二、底下栏会出现Services 然后右键添加工程即可

Apache DolphinScheduler 3.1.8 版本发布,修复 SeaTunnel 相关 Bug

近日&#xff0c;Apache DolphinScheduler 发布了 3.1.8 版本。此版本主要基于 3.1.7 版本进行了 bug 修复&#xff0c;共计修复 16 个 bug, 1 个 doc, 2 个 chore。 其中修复了以下几个较为重要的问题&#xff1a; 修复在构建 SeaTunnel 任务节点的参数时错误的判断条件修复 …

【学习笔记】Java安全之反序列化

文章目录 反序列化方法的对比PHP的反序列化Java的反序列化Python反序列化 URLDNS链利用链分析触发DNS请求 CommonCollections1利用链利用TransformedMap构造POC利用LazyMap构造POCCommonsCollections6 利用链 最近在学习Phith0n师傅的知识星球的Java安全漫谈系列&#xff0c;随…