【LeetCode】链表oj专题

前言

经过前面的学习,咋们已经学完了链表相关知识,这时候不妨来几道链表算法题来巩固一下吧!

如果有不懂的可翻阅之前文章哦!

个人主页:小八哥向前冲~-CSDN博客

数据结构专栏:数据结构【c语言版】_小八哥向前冲~的博客-CSDN博客

c语言专栏:c语言_小八哥向前冲~的博客-CSDN博客

这里的题目都是非常经典的好题目哦!能让我们对链表的理解更深一步!

当然,有些题目非常有意思哦!哈哈哈哈!我们一起来看看!

目录

前言

1.反转链表

2.删除链表节点

3.寻找中间节点

4.环形链表的约瑟夫问题

5.合并有序链表

6.输出倒数k节点

7.链表的回文结构

8.判断相交链表

9.环形链表

10.环形链表2

11.随机链表的复制


1.反转链表

题目

给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。

题目详情:LCR 024. 反转链表 - 力扣(LeetCode)

思路

看到这道题是不是觉得稳了?是不是觉得很简单?

我们只需要一个一个节点遍历链表,将一个个节点按顺序拿下来头插不就行了!

上图理解:

代码

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

思路2

创建哨兵位节点,将原链表遍历,把每个链表一个一个尾插到哨兵位的后面

是不是也很简单?上图理解一下:

代码

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head){ListNode*cur=head;//创建哨兵位节点ListNode*newhead=(ListNode*)malloc(sizeof(ListNode));newhead->next=NULL;while(cur){ListNode*next=cur->next;cur->next=newhead->next;newhead->next=cur;cur=next;}return newhead->next;
}

2.删除链表节点

题目

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。

详情:LCR 136. 删除链表的节点 - 力扣(LeetCode)

思路

创建一个哨兵位,遍历原链表,将不是指定节点全部拿下来尾插,得到新的链表!

上图解释一下:

代码

typedef struct ListNode ListNode;struct ListNode* deleteNode(struct ListNode* head, int val){ListNode*newhead=(ListNode*)malloc(sizeof(ListNode));ListNode*tail=newhead;ListNode*cur=head;while(cur){if(cur->val!=val){tail->next=cur;tail=cur;}cur=cur->next;}tail->next=NULL;return newhead->next;
}

3.寻找中间节点

题目

给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

详情:876. 链表的中间结点 - 力扣(LeetCode)

思路

定义两个指针(快慢指针),快指针走两步,慢指针走一步,最终慢指针便是中间节点!但是需要分奇数链表和偶数链表。

上图:

代码

 typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {ListNode*slow,*fast;//快慢指针,慢指针走一步,快指针走两步slow=fast=head;while(fast&&fast->next)//两种情况,一种节点为奇数,一种节点为偶数{slow=slow->next;fast=fast->next->next;}   return slow; 
}

4.环形链表的约瑟夫问题

题目

详情:环形链表的约瑟夫问题_牛客题霸_牛客网 (nowcoder.com)

思路

1.创建链表节点

2.将节点连成环

3.开始纱人

图:

代码

 typedef struct ListNode ListNode;
//创建链表节点函数
ListNode*Buynode(int x)
{ListNode*node=(ListNode*)malloc(sizeof(ListNode));node->val=x;node->next=NULL;return node;
}
//将节点连成环,创建循环链表
ListNode* NodeCircle(int n)
{//先创建第一个节点ListNode*phead=Buynode(1);ListNode*ptail=phead;for(int i=2;i<=n;i++){ptail->next=Buynode(i);ptail=ptail->next;}ptail->next=phead;//将节点连起来return ptail;
}
int ysf(int n, int m ) {// write code hereListNode*prev=NodeCircle(n);ListNode*pcur=prev->next;int count=1;while(pcur->next!=pcur)//最后只剩一个人,它的下一个节点是它自己{if(count==m)//数到m就自杀{prev->next=pcur->next;free(pcur);pcur=prev->next;count=1;//当杀完后,置为1,重新数数}else{//没数到m就开始数(挪prev和pcur位置)prev=pcur;pcur=pcur->next;count++;}}return pcur->val;
}

5.合并有序链表

题目

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

详情:21. 合并两个有序链表 - 力扣(LeetCode)

思路

同时遍历两个链表和创建一个哨兵位,每个节点每个节点进行比较,小的那个节点尾插到带头哨兵后面,注意当其中有一个为空时,则另一个还未尾插完!

上图理解:

代码

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {ListNode*l1=list1;ListNode*l2=list2;ListNode*newhead,*newtail;newhead=newtail=(ListNode*)malloc(sizeof(ListNode));//哨兵节点while(l1&&l2){if(l1->val<l2->val){//将l1拿下来尾插newtail->next=l1;newtail=newtail->next;l1=l1->next;}else{//将l2拿下来尾插newtail->next=l2;newtail=newtail->next;l2=l2->next;}}//跳出循环有两种情况,要么l1没尾插完,要么l2没尾插完if(l1==NULL){newtail->next=l2;//newtail=newtail->next;}if(l2==NULL){newtail->next=l1;//newtail=newtail->next;}return newhead->next;
}

6.输出倒数k节点

题目

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

思路

定义快慢指针,但这里的快慢指针并不是和寻找中间节点那个快慢指针一样!听我道来。

这里要找倒数第几个节点,快指针就先走几个节点!随后一起俩指针一起走。当快指针走到空时,慢指针指向的就是倒数k节点!

图:

代码

typedef struct ListNode ListNode;
int kthToLast(struct ListNode* head, int k){//定义快慢指针,快指针开始就比满指针快k步,随后一直一步一步走ListNode*slow=head,*fast=head;while(k--){fast=fast->next;}//随后一起走,当快指针走到空,慢指针就是那个节点while(fast){fast=fast->next;slow=slow->next;}return slow->val;
}

7.链表的回文结构

题目

给定一个链表的 头节点 head ,请判断其是否为回文链表。

如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。

详情:LCR 027. 回文链表 - 力扣(LeetCode)

注意:这题目很经典很重要!需要掌握!

思路

先找到中间节点,再反转中间节点之后的节点!定义俩个指针一个头指针,一个中间节点指针。

俩指针同时遍历比较,途中但凡没有相同的就不是回文结构!

是不是觉得很简单?没错,其实主要就掌握链表的反转和寻找链表的中间节点就行!

上图:

代码

typedef struct ListNode ListNode;
//寻找中间节点函数
ListNode*MidNode(ListNode*head)
{//快慢指针ListNode*slow=head,*fast=head;//慢指针走一步,快指针走两步while(fast&&fast->next){slow=slow->next;fast=fast->next->next;}//慢指针就是中间节点return slow;
}
//翻转节点函数
ListNode*reverse(ListNode*head)
{ListNode*newhead=NULL,*cur=head;while(cur){ListNode*next=cur->next;cur->next=newhead;newhead=cur;cur=next;}return newhead;
}
bool isPalindrome(struct ListNode* head){ListNode*mid=MidNode(head);ListNode*head1=head;ListNode*head2=reverse(mid);while(head2&&head1){if(head1->val!=head2->val){return false;}head1=head1->next;head2=head2->next;}return true;
}

8.判断相交链表

题目

给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null 。

详情:LCR 023. 相交链表 - 力扣(LeetCode)

思路

分别遍历俩链表且计算俩链表的长度。如果最后一个节点(地址)相同(注意这里不要用值比较,可能不是一个节点只是值相同而已!),计算出长的链表,先走相差步(俩链表相减的绝对值)

最终同时遍历,一直比较,直到比较到俩链表的相同节点,就找到了相交节点!

代码

 typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {ListNode*curA=headA,*curB=headB;int lenA=0,lenB=0;while(curA->next){lenA++;curA=curA->next;}while(curB->next){lenB++;curB=curB->next;}if(curA!=curB){return NULL;}int tmp=abs(lenA-lenB);ListNode*shortList=headA,*longList=headB;if(lenA>lenB){shortList=headB;longList=headA;}while(tmp--){longList=longList->next;}while(shortList!=longList){shortList=shortList->next;longList=longList->next;}return shortList;
}

9.环形链表

题目

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

详情:141. 环形链表 - 力扣(LeetCode)

思路

定义快慢指针,慢指针走一步,快指针走两步,如果没有环就是寻找中间节点的情景,如果有环,因为有速度差又是闭合的环状,最终会追到!

代码

bool hasCycle(struct ListNode *head) {struct ListNode*slow=head,*fast=head;//如果没有环,分奇数偶数情况,奇数fast->next为空,偶数fast为空while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){return true;}}return false;
}

拓展

俩个问题:

  1. 一定会追到吗?有没有可能会错过?请证明一下!
  2. 如果快指针走3步呢?还追得上吗?如果慢指针走俩步呢?又追不追得上?

第一个问题解答

一定会追上!慢指针走一步,快指针走俩步一定会追上!

慢指针走一步,快指针走俩步,它们的相对速度其实就是一步!什么意思呢?它们之间的距离会一步一步的减少,就是因为是一步一步的减少才不会错过!

第二个问题解答

如果快指针走三步,慢指针走一步的话,不一定能追上!因为它们的相对速度是2步,可能会错过!

如果当慢指针进环时,快指针和慢指针的距离如果是偶数的话,就能追上!

如果当慢指针进环时,快指针和慢指针的距离如果是奇数的话,就错过了!那么开始第二圈的追逐!当开始追的时候,它们的距离如果是偶数,第二圈就追上了!如果是奇数,第二圈追不上,那么之后永远追不上!

上图解释一下第二个问题:

10.环形链表2

题目

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

详情:142. 环形链表 II - 力扣(LeetCode)

思路1

仍然定义快慢指针,快指针走俩步,慢指针走一步,最终会追到一起!

再将追到一起的节点和头节点一起遍历,当俩指针相等时则就是环链表的入口节点。

你是不是有疑问?为什么俩指针相等时就是环链表的入口节点?

我们上图解释一下:

代码


struct ListNode *detectCycle(struct ListNode *head) {struct ListNode*slow=head,*fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){struct ListNode*meet=slow;struct ListNode*cur=head;while(meet!=cur){meet=meet->next;cur=cur->next;}return cur;}}return NULL;
}

思路2

还是定义快慢指针,慢指针走一步,快指针走俩步,最终终会追上!

将相逢节点断开,然后就变成了俩个链表,问题变成了在相交链表中寻找相交节点!

上图:

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/
struct ListNode*Intersect(struct ListNode*head1,struct ListNode*head2)
{struct ListNode*cur1=head1,*cur2=head2;int len1=0,len2=0;while(cur1){cur1=cur1->next;len1++;}while(cur2){cur2=cur2->next;len2++;}int tmp=abs(len1-len2);struct ListNode*shortList=head1,*longList=head2;if(len1>len2){longList=head1;shortList=head2;}//长的先走相差步while(tmp--){longList=longList->next;}while(longList!=shortList){longList=longList->next;shortList=shortList->next;}return longList;
}struct ListNode *detectCycle(struct ListNode *head) {struct ListNode*slow=head,*fast=head;while(fast&&fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){//将环拆开,变成寻找两链表的中间节点fast=fast->next;slow->next=NULL;return Intersect(fast,head);//寻找两链表的中间节点}}return NULL;
}

11.随机链表的复制

题目

详情:138. 随机链表的复制 - 力扣(LeetCode)

思路

1.遍历原链表,一个一个创建新节点连接到原节点的后面!

2.再遍历原链表,按照原链表randrom的连接来连接新节点!

3.再遍历,从原链表上面拆解新链表下来!(尾插)

图文理解:

代码

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;copy->next=cur->next;cur->next=copy;cur=copy->next;}//给拷贝节点的random赋值cur=head;while(cur){struct Node*copy=cur->next;if(cur->random==NULL){copy->random=NULL;}else{//控制random的值copy->random=cur->random->next;}cur=copy->next;}//将拷贝节点拆下来(尾插)cur=head;struct Node*newhead=NULL,*newtail=NULL;while(cur){struct Node*copy=cur->next;struct Node*next=copy->next;if(newhead==NULL){newhead=newtail=copy;}else{newtail->next=copy;newtail=newtail->next;}//恢复原链表结构,也可以不恢复cur->next=next;cur=next;}return newhead;
}

今天的算法题就分享到这里吧!这些题目都是很经典的哦!

我们下期见!

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

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

相关文章

【管理篇】如何处理团队里的老资格员工和高能力员工?

目录标题 两类员工对比&#x1f93a;老资格员工高能力员工 作为领导你应该怎么做&#xff1f; 在管理团队时&#xff0c;处理老资格员工和高能力员工是一项至关重要的任务。这两类员工在团队中扮演着不同的角色和有着不同的需求&#xff0c;因此需要针对性的管理和激励。下面将…

漫谈音频深度伪造技术

作为人工智能时代的新型媒体合成技术&#xff0c;深度伪造技术近年来在网络媒体中的涉及领域越发广泛、出现频次越发频繁。据路透社报道&#xff0c;2023年&#xff0c;社交媒体网站上发布50万个深度伪造的语音和视频。 1、深度伪造技术的五个方面 音频深度伪造技术&#xff…

Java八股文3

3.垃圾回收 1.对象什么时候可以被垃圾器回收 1.垃圾回收的概念 为了让程序员更专注于代码的实现&#xff0c;而不用过多的考虑内存释放的问题&#xff0c;所以&#xff0c; 在Java语言中&#xff0c;有了自动的垃圾回收机制&#xff0c;也就是我们熟悉的GC(Garbage Collection)…

Unity 性能优化之静态批处理(三)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、静态批处理是什么&#xff1f;二、使用步骤1.勾选Static Batching2.测试静态合批效果 三、静态合批得限制1、游戏对象处于激活状态。2、游戏对象有一…

CMakeLists.txt语法规则:条件判断说明一

一. 简介 前面学习了 CMakeLists.txt语法中的 部分常用命令&#xff0c;常量变量&#xff0c;双引号的使用。 本文继续学习 CMakeLists.txt语法中的条件判断。 二. CMakeLists.txt 语法规则&#xff1a;条件判断 在 cmake 中可以使用条件判断&#xff0c;条件判断形式如下…

STM32 01

1、编码环境 1.1 安装keil5 1.2 安装STM32CubeMX 使用STM32CubeMX可以通过界面的方式&#xff0c;快速生成工程文件 安装包可以从官网下载&#xff1a;https://www.st.com/zh/development-tools/stm32cubemx.html#overview 安装完要注意更新一下固件包的位置&#xff0c;因为…

vivado 在硬件中调试串行 I/O 设计-属性窗口

只要在“硬件 (Hardware) ”窗口中选中 GT 或 COMMON 块、在“链接 (Link) ”窗口中选中链接 &#xff0c; 或者在“扫描 (Scan)”窗口中选中扫描 &#xff0c; 那么就会在“ Properties ”窗口中显示该对象的属性。对于 GT 和 COMMON &#xff0c; 包括这些对象的所有属性、…

电商日志项目(一)

电商日志项目 一、项目体系架构设计1. 项目系统架构2. 项目数据流程二、环境搭建1. NginxLog文件服务1.1. 上传,解压1.2. 编译安装1.3. 启动验证2. Flume-ng2.1. 上传解压2.2. 修改配置文件2.3. 修改环境变量2.4. 验证3. Sqoop3.1. 上传解压3.2. 配置环境变量3.3. 修改配置文件…

如何进行Go语言的性能测试和调优?

文章目录 开篇一、性能测试1. 使用标准库中的testing包2. 使用第三方工具 二、性能调优1. 优化算法和数据结构2. 减少不必要的内存分配和垃圾回收3. 并发和并行 结尾 开篇 Go语言以其出色的性能和简洁的语法受到了广大开发者的喜爱。然而&#xff0c;在实际开发中&#xff0c;…

微服务架构与单体架构

微服务架构与与单体架构比较 微服务架构是一种将应用程序作为一组小的、独立服务的系统架构风格&#xff0c;每个服务运行在其自己的进程中&#xff0c;并通常围绕业务能力组织。这些服务通过定义良好且轻量级的机制&#xff08;通常是HTTP REST API&#xff09;进行通信。微服…

Redis(基础指令和五大数据类型)

文章目录 1.基本介绍1.多种数据结构支持2.应用场景 2.Redis安装&#xff08;直接安装到云服务器&#xff09;1.安装gcc1.yum安装gcc2.查看gcc版本 2.将redis6.2.6上传到/opt目录下3.进入/opt目录下然后解压4.进入 redis-6.2.6目录5.编译并安装6.进入 /usr/local/bin 查看是否有…

智慧文旅开启沉浸式文化体验,科技让旅行更生动:借助智慧技术,打造沉浸式文化体验场景,让旅行者在旅行中深度感受文化的魅力

一、引言 随着科技的飞速发展&#xff0c;传统旅游行业正经历着前所未有的变革。智慧文旅&#xff0c;作为一种新兴的旅游模式&#xff0c;正以其独特的魅力&#xff0c;吸引着越来越多的旅行者。智慧文旅不仅改变了人们的旅行方式&#xff0c;更在深度上丰富了人们的文化体验…

Spring入门及注解开发

1 引言 自定义注解可以用来为代码添加元数据信息,简化配置,提高代码的可读性和可维护性。通过自定义注解,可以实现自定义的业务逻辑、约束条件、配置参数等功能。在Spring中,自定义注解常用于标记组件、配置依赖注入、AOP切面等。 自定义注解可以添加元数据信息,低代码框…

关于图形库

文章目录 1. 概念介绍2. 使用方法2.1 普通路由2.2 命名路由 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示Dialog"相关的内容&#xff0c;本章回中将介绍使用get进行路由管理.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

AEC Capital Limited:开启可持续金融新纪元

在当今社会&#xff0c;环保和可持续发展已成为全球关注的焦点。在这个背景下&#xff0c;AEC Capital Limited作为香港的一家金融服务公司&#xff0c;以其专业、高端的服务和创新的理念&#xff0c;成为可持续金融领域的引领者。我们致力于将环境保护与金融服务相结合&#x…

观测与预测差值自动变化系统噪声Q的自适应UKF(AUKF_Q)MATLAB编写

简述 基于三维模型的UKF&#xff0c;设计一段时间的输入状态误差较大&#xff0c;此时通过对比预测的状态值与观测值的残差&#xff0c;在相应的情况下自适应扩大系统方差Q&#xff0c;构成自适应无迹卡尔曼滤波&#xff08;AUKF&#xff09;&#xff0c;与传统的UKF相比&…

mac监听 linux服务器可视化(Grafana+Promethus+Node_exporter)

Grafana和promethus(普罗米修斯)的安装和使用 监控系统的Prometheus类似于一个注册中心&#xff0c;我们可以只需要配置一个Prometheus,而在其他服务器&#xff0c;只需要安装node_exporter,它们的数据流转就是通过exporter采集数据信息&#xff0c;然后告诉prometheus它的位置…

华为二层交换机与路由器连通上网实验

华为二层交换机与路由器连通上网实验 二层交换机是一种网络设备&#xff0c;用于在局域网&#xff08;LAN&#xff09;中转发数据帧。它工作在OSI模型的第二层&#xff0c;即数据链路层。二层交换机通过学习和维护MAC地址表&#xff0c;实现了数据的快速转发和广播域的隔离。 实…

CGAL 网格简化

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 为了提高网格处理的效率,通常需要将过于冗长的3D数据集简化为更简洁而又真实的表示。尽管从几何压缩到逆向工程有许多应用,但简洁地捕捉表面的几何形状仍然是一项乏味的任务。CGAL中则为我们提供了一种通过变分几…

基于LLama3、Langchain,Chroma 构建RAG

概要&#xff1a; 使用Llama3 Langchain和ChromaDB创建一个检索增强生成&#xff08;RAG&#xff09;系统。这将允许我们询问有关我们的文档&#xff08;未包含在训练数据中&#xff09;的问题&#xff0c;而无需对大型语言模型&#xff08;LLM&#xff09;进行微调。在使用RA…