leetcode每日一练:链表OJ题

链表经典算法OJ题

1.1 移除链表元素

题目要求:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

解题思路:

思路1:

定义两个指针,一个指向当前节点,一个指向当前节点的下一个节点,如果下一个节点是要删除的节点就将当前节点的next存储下一个节点的再下一个节点的地址,然后free那个节点。知道遍历完原链表,该思路是改变原链表。

思路2:

建立一个新的链表,遍历原链表,将原链表中的非删除节点给新的链表,遍历结束后新链表中没有要删除节点。

struct ListNode{int val;struct ListNode *next;
};
struct ListNode* removeElements(struct ListNode* head, int val) {struct ListNode* Newhead, * NewTail;//一个头链表,一个链表尾部Newhead = NewTail = NULL;//遍历原链表struct ListNode* pcur = head;while (pcur){if (pcur->val != val){if (Newhead == NULL){Newhead = NewTail = pcur;}else{NewTail->next = pcur;NewTail = NewTail->next;}}pcur = pcur->next;}//如果要删除值在原链表为节点,新链表的尾节点就不会指向NULL,所以这里要判断if (NewTail){NewTail->next = NULL;}return Newhead;
}

1.2 反转链表

题目要求:

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

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?

解题思路:

可以定义三个新的节点类型的指针变量n1、n2、n3。然后就可以使用这三个指针来反转链表。首先n1初始化为NULL,n2初始化为head链表头结点,n3则是head头结点的下一个节点。然后循环n2->next = n1, n1 = n2, n2 = n3,n3 = n3->next。循环往复就完成了反转链表的操作。

typedef struct ListNode{int val;struct ListNode *next;
}*pList;//反转链表函数实现
pList reverselist(pList head){if (head == NULL){return NULL;}pList n1, n2, n3;n1 = NULL, n2 = head, n3 = head->next;while (n2){n2->next = n1;n1 = n2;n2 = n3;if(n3)//如果n3为NULL就不再向后访问了n3 = n3->next;}return n1;
}//以下调用上面函数的main是我自己写的,可以供大家参考
int main()
{//创建链表struct ListNode* phead, *pTail, *p;phead = pTail = NULL;int n = 0;printf("请输入要创建链表节点个数:>");scanf("%d", &n);int i = 0;for (i = 0; i < n; i++){p = (pList)malloc(sizeof(struct ListNode));printf("请输入第%d个节点的值:>", i + 1);scanf("%d", &(p->val));p->next = NULL;if (phead == NULL){phead = p;pTail = phead;}else{pTail->next = p;pTail = pTail->next;}}//调用反转链表函数pList Newhead = reverselist(phead);if (Newhead == NULL){perror("reverselist");return;}phead = Newhead;//打印链表节点数据while (Newhead){printf("%d->", Newhead->val);Newhead = Newhead->next;}printf("NULL\n");i = 1;Newhead = phead;//销毁链表while (Newhead){phead = phead->next;free(Newhead);Newhead = phead;printf("已释放第%d条节点\n", i);i++;}return 0;
}

1.3 合并两个有序链表

题目要求:

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

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

解题思路:

定义两个新的节点指针,一个头节点,一个尾结点。比较两个原链表当前节点的数据大小,然后插入新的链表,知道插完为止

typedef struct ListNode {int val;struct ListNode* next;
}*pList;
//合并两个有序链表函数实现
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {if (list1 == NULL){return list2;}if (list2 == NULL){return list1;}struct ListNode* cur1, *cur2;cur1 = list1, cur2 = list2;struct ListNode* phead, * pTail;phead = pTail = (struct ListNode*)malloc(sizeof(struct ListNode));while (cur1 && cur2) {if (cur1->val < cur2->val){pTail->next = cur1;pTail = pTail->next;cur1 = cur1->next;}else{pTail->next = cur2;pTail = pTail->next;cur2 = cur2->next;}}if (cur1) {pTail->next = cur1;}if (cur2) {pTail->next = cur2;}struct ListNode* retList = phead->next;free(phead);return retList;
}
//以下创建链表调用函数的代码是自己写的,只为调用上面函数,不是链表规范创建。仅供参考
int main()
{struct ListNode* phead1, pTail1, p1;struct ListNode* phead2, pTail2, p2;phead1 = pTail1 = NULL;phead2 = pTail2 = NULL;int n = 0;printf("请输入要创建p1和p2链表节点个数:>");scanf("%d", &n);int i = 0;for (i = 0; i < n; i++){p1 = (pList)malloc(sizeof(struct ListNode));p2 = (pList)malloc(sizeof(struct ListNode));printf("请输入p1链表第%d个节点的值:>", i + 1);scanf("%d", &(p1->val));printf("请输入p2链表第%d个节点的值:>", i + 1);scanf("%d", &(p2->val));p1->next = NULL;p2->next = NULL;if (phead1 == NULL && phead2 == NULL){phead1 = p1;pTail1 = phead1;phead2 = p2;pTail2 = phead2;}else{pTail1->next = p1;pTail1 = pTail1->next;pTail2->next = p2;pTail2 = pTail2->next;}}pList Newhead = mergeTwoLists(phead1,phead2);if (Newhead == NULL){perror("reverselist");return;}pList phead = Newhead;while (Newhead){printf("%d->", Newhead->val);Newhead = Newhead->next;}printf("NULL\n");i = 1;Newhead = phead;while (Newhead){phead = phead->next;free(Newhead);Newhead = phead;printf("已释放第%d条节点\n", i);i++;}return 0;
}

1.4 链表的中间节点

题目要求:

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

示例 2:

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

解题思路:

快慢指针:使用快慢指针来遍历链表,慢指针每次走一步,快指针每次走两步,当快指针走到最后慢指针刚好走到中间节点。因为快指针是慢指针的2倍。所以快指针从起点到终点时慢指针就是这个路程的一半,是中点。

typedef struct ListNode{int val;struct ListNode* next;
}*pList;
//函数实现
struct ListNode* middleNode(struct ListNode* head) {if (head == NULL){return NULL;}struct ListNode* slow, *fast;slow = fast = head;//节点数可能是奇数个也可能是偶数个,所以要两种判断while (fast && fast->next) {slow = slow->next;fast = fast->next->next;}return slow;
}

1.5 环形链表的约瑟夫问题

著名的Josephus问题

据说著名的历史学家 Josephus有过以下的故事:故事据说发生在古罗马时期,在罗马人占领乔塔帕特后,39个犹太人与约瑟夫及他的朋友躲到一个洞中,他们宁愿死也不要被敌人抓到,于是约定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下1个人重新报数,直到所有人都自杀身亡为止。

然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

题目要求:

编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。

下一个人继续从 1 开始报数。

n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?

数据范围: 1≤𝑛,𝑚≤100001≤n,m≤10000

进阶:空间复杂度 𝑂(1)O(1),时间复杂度 𝑂(𝑛)O(n)

示例1

输入:

5,2     

复制返回值:

3    

复制说明:

开始5个人 1,2,3,4,5 ,从1开始报数,1->1,2->2编号为2的人离开
1,3,4,5,从3开始报数,3->1,4->2编号为4的人离开
1,3,5,从5开始报数,5->1,1->2编号为1的人离开
3,5,从3开始报数,3->1,5->2编号为5的人离开
最后留下人的编号是3      

示例2

输入:

1,1

返回值:

1
typedef struct ListNode ListNode;创建一个节点并返回
ListNode* ListBuyNode(int val)
{ListNode* ret = (ListNode*)malloc(sizeof(ListNode));if(ret==NULL){perror("malloc");return NULL;}ret->val = val;ret->next = NULL;return ret;
}
//创建一个环形链表并返回
ListNode* CreatNode(int n)
{ListNode* phead = ListBuyNode(1);ListNode* pTail = phead;int i = 0;for(i=2;i<=n;i++){pTail->next = ListBuyNode(i);pTail = pTail->next;}pTail->next = phead;//将链表循环return pTail;
}int ysf(int n, int m ) {// write code hereListNode* prev = CreatNode(n);ListNode* cur = prev->next;int count = 1;//遍历判断while(cur->next!=cur){if(count == m){prev->next = cur->next;free(cur);cur = prev->next;count = 1;}else{prev = cur;cur = cur->next;count++;}}return cur->val;
}

1.6 分隔链表

题目要求:

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你应当 保留 两个分区中每个节点的初始相对位置。

示例 1:

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]

示例 2:

输入:head = [2,1], x = 2
输出:[1,2]

解题思路:

大小链表:我们可以创建两个新的链表,为大小链表。遍历原链表。大于等于x的节点连接在大链表,小于x的节点连接在小链表。最后将大链表的头结点连接在小链表的尾结点。返回小链表的头结点

typedef struct ListNode {int val;struct ListNode* next;
}*pList;//分隔链表的函数实现
struct ListNode* partition(struct ListNode* head, int x) {if (head == NULL){return NULL;}struct ListNode* lessHead, * lessTail;struct ListNode* greaterHead, * greaterTail;//定义哨兵位lessHead = lessTail = (struct ListNode*)malloc(sizeof(struct ListNode));greaterHead = greaterTail = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* pcur = head;//用来遍历原链表//分隔操作while (pcur){if (pcur->val >= x){greaterTail->next = pcur;greaterTail = greaterTail->next;}else{lessTail->next = pcur;lessTail = lessTail->next;}pcur = pcur->next;}//将大小链表连接起来lessTail->next = greaterHead->next;if(greaterTail)greaterTail->next = NULL;//释放哨兵位free(greaterHead);struct ListNode* retList = lessHead->next;free(lessHead);//返回头结点return retList;
}
int main()
{pList phead, pTail, p;phead = pTail = NULL;int n = 0;printf("请输入要创建链表节点个数:>");scanf("%d", &n);int i = 0;for (i = 0; i < n; i++){p = (pList)malloc(sizeof(struct ListNode));printf("请输入第%d个节点的值:>", i + 1);scanf("%d", &(p->val));p->next = NULL;if (phead == NULL){phead = p;pTail = phead;}else{pTail->next = p;pTail = pTail->next;}}pList Newhead = partition(phead, 3);if (Newhead == NULL){perror("reverselist");return;}phead = Newhead;while (Newhead){printf("%d->", Newhead->val);Newhead = Newhead->next;}printf("NULL\n");i = 1;Newhead = phead;while (Newhead){phead = phead->next;free(Newhead);Newhead = phead;printf("已释放第%d条节点\n", i);i++;}return 0;
}

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

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

相关文章

学习java第一百一十八天

Component 和 Bean 的区别是什么&#xff1f;Component 注解作用于类&#xff0c;而Bean注解作用于方法。Component通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中&#xff08;我们可以使用 ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装…

Nacos 配置中心:动态加载 Bean

前提&#xff1a; 已经集成好 springboot / cloud 与nacos的环境 1 nacos中配置文件参数 message:#sender: emailMessageSendersender: smsMessageSender 2 接口和两个实现类 public interface MessageSender {String sendMessage(String message, String recipient); }impo…

模电-二极管及其应用51单片机LED点亮前置工作!

今日小记 2024-7-2&#xff0c;星期二&#xff0c;16:32&#xff0c;天气&#xff1a;晴&#xff0c;心情&#xff1a;晴。持续了两个星期的梅雨天终于暂时过去啦&#xff0c;迎来了久违的阳光&#xff0c;虽然没有雨天凉快&#xff0c;但是能看到太阳也是开心哒&#xff0c;心…

2021强网杯

一、环境 网上自己找 二、步骤 2.1抛出引题 在这个代码中我们反序列&#xff0c;再序列化 <?php$raw O:1:"A":1:{s:1:"a";s:1:"b";};echo serialize(unserialize($raw));//O:1:"A":1:{s:1:"a";s:1:"b";…

工业 web4.0UI 风格品质卓越

工业 web4.0UI 风格品质卓越

深入理解 RabbitMQ、RocketMQ等常⽤的消息中间件进⾏消息的异步数据处理

深入理解消息中间件对于构建高可用、高性能的分布式系统至关重要。以下是对RabbitMQ和RocketMQ这两种常用消息中间件的异步数据处理的深入理解&#xff1a; ### RabbitMQ RabbitMQ是一个开源的消息代理&#xff0c;它支持多种消息协议&#xff0c;如AMQP、STOMP等&#xff0c;…

单向链表结构

链表结构简介 链表结构是一种用比较特殊的数据结构类型&#xff0c;它也是线性数据结构中的一种&#xff0c;但是与栈结构等线性数据结构不同&#xff0c;它的内部结构并不是一个简单的存储空间&#xff0c;而是一个带有指向性质的单元。要理解链表结构要弄清楚两个问题&#x…

不要再被骗了!电脑无法进入系统的原因可能是这个硬件坏了而已……

前言 前段时间小白在抖音上发了很多很多很多的视频&#xff0c;其中应该是有很多商家关注了小白。 然后就会出现很多很多很多的赚钱小门道…… 电脑开机没有显示&#xff1f;换显卡&#xff01; 电脑还是不开机&#xff1f;换CPU 电脑还是一样不开机…… 经过了一番大折腾…

10.8K star!史上最强Web应用防火墙雷池WAF

长亭雷池SafeLine是长亭科技耗时近 10 年倾情打造的WAF(Web Application Firewall)&#xff0c; 一款敢打出口号 “不让黑客越雷池一步” 的 WAF&#xff0c;愿称之为史上最强的一款Web应用防火墙&#xff0c;足够简单、足够好用、足够强的免费且开源的 WAF&#xff0c;基于业…

AI为小微企业赋能:解锁数字化转型的金钥匙

AI为小微企业赋能&#xff1a;解锁数字化转型的金钥匙 在当今全球经济加速迭代的背景下&#xff0c;小微企业作为社会经济肌体的毛细血管&#xff0c;面临着前所未有的挑战与机遇。人工智能&#xff08;AI&#xff09;的崛起&#xff0c;如同一股强大的科技旋风&#xff0c;为…

binlog区分业务修改还是手动修改

一、Windows下开启MySQL binLog日志 首先要开启MySQL的BinLog 管理 show variables like %log_bin%;如果发现log_bin是OFF&#xff0c;打开mysql文件夹下面的my.ini&#xff0c;修改一下 在 [mysqld] 下面加 # 开启bin-log log-binmysql-bin # 开启binlog功能 binl…

pads layout 脚本导出不能运行excle解决办法

在一台新的电脑上安装好PADS&#xff0c;打开PCB文件导出坐标文件时&#xff1a; 出现“ActiveX Automation: server could not be found.”的问题,导致无法成功导出文件,错误提示截图如下&#xff1a; 导致上述问题的原因是在我们配置导出带坐标的脚本时,默认使用的是微软…

Java 实现application/x-www-form-urlencoded编码格式的POST请求

一、实现方式 在Java中&#xff0c;实现application/x-www-form-urlencoded内容类型通常涉及到发送HTTP POST请求。你可以使用java.net.HttpURLConnection或者第三方库如Apache HttpClient来实现。 以下是使用HttpURLConnection发送application/x-www-form-urlencoded数据的代…

linux的shell脚本编程详解

Shell 脚本是一种用于自动化任务的脚本语言&#xff0c;在 Linux 和其他类 Unix 操作系统中非常流行。它通常用于任务自动化、系统管理和批处理。编写 Shell 脚本并使其自动化编译过程&#xff08;例如使用 gcc 编译 C/C 程序&#xff09;是一种常见的任务。 以下是一个详细的…

昇思MindSpore学习笔记3--张量 Tensor

一、张量Tensor概念 矢量、标量和其他张量的计算函数&#xff0c;有内积、外积、线性映射以及笛卡儿积等 张量坐标在 n 维空间内&#xff0c;有 nr 个分量 每个分量都是坐标的函数,变换时每个坐标分量都按规则作线性变换 张量是一种特殊的数据结构&#xff0c;类似于数组和…

利用深度学习模型进行语音障碍自动评估

语音的产生涉及器官的复杂协调&#xff0c;因此&#xff0c;语音包含了有关身体各个方面的信息&#xff0c;从认知状态和心理状态到呼吸条件。近十年来&#xff0c;研究者致力于发现和利用语音生物标志物——即与特定疾病相关的语音特征&#xff0c;用于诊断。随着人工智能&…

js基础学习

1、js概述 js是javascript的简称&#xff0c;作用是实现页面和用户的交互 js由浏览器解析运行&#xff0c;不需要编译 js由es基础语法&#xff0c;bom浏览器相关&#xff0c;dom文档操作相关 三大部分组成 2、html引入js <!DOCTYPE html> <html lang"zh-CN&qu…

Vue项目打包上线

Nginx 是一个高性能的开源HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP代理服务器。它在设计上旨在处理高并发的请求&#xff0c;是一个轻量级、高效能的Web服务器和反向代理服务器&#xff0c;广泛用于提供静态资源、负载均衡、反向代理等功能。 1、下载nginx 2、…

k8s学习--k8s群集ELK日志收集部署最详细的过程与应用(收集k8s群集日志)(图形化界面手把手教学)

文章目录 FilebeatFilebeat主要特点Filebeat使用场景 ELK简介Elasticsearch简介Elasticsearch主要特点Elasticsearch使用场景 Logstash简介Logstash主要特点Logstash使用场景 Kibana简介Kibana主要特点Kibana使用场景 简单理解 环境一、ELK集群部署1.软件安装2.软件配置及启动(…

Webpack: Loader开发 (2)

概述 在上一篇文章中&#xff0c;我们已经详细了解了开发 Webpack Loader 需要用到的基本技能&#xff0c;包括&#xff1a;Loader 基本形态、如何构建测试环境、如何使用 Loader Context 接口等。接下来我们继续拓展学习一些 Loader 辅助工具&#xff0c;包括&#xff1a; 了…