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

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

目录

一、移除链表元素

二、链表的中间结点

三、链表中倒数第k个结点

四、反转链表

五、合并两个有序链表

六、分割链表


一、移除链表元素

题目描述:力扣

法一:直接循环依次判断

对于这个题目,我们最容易想到的一种思路就是,直接遍历链表,当链表的值是需要删除的时候,直接删除即可,然后改变连接关系即可

代码如下

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){struct ListNode* cur=head;struct ListNode* prev=NULL;while(cur!=NULL){if(cur->val!=val){prev=cur;cur=cur->next;}else {if(head==cur){head=cur->next;free(cur);cur=head;}else{struct ListNode* next=cur->next;free(cur);prev->next=next;cur=next;}}}return head;
}

对于我们写的这个代码,我们有以下几点需要注意:

1.当头结点就是需要删除的时候,那么prev是为空的,所以我们需要特殊处理,采用头删的思路即可。

2.这个函数传递的是一级指针,而非二级指针,原因是题目要求最后返回了头结点。所以可以不使用二级指针。

3.当代码出现问题,而在力扣上无法肉眼观察出错误的时候,我们就需要放到vs上进行调试,那么就涉及到需要自己手搓一个链表的问题,手搓的方法如下所示

int main()
{struct ListNode* n1 = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* n2 = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* n3 = (struct ListNode*)malloc(sizeof(struct ListNode));struct ListNode* n4 = (struct ListNode*)malloc(sizeof(struct ListNode));n1->val = 1;n2->val = 2;n3->val = 3;n4->val = 4;n1->next = n2;n2->next = n3;n3->next = n4;n4->next = NULL;
}

法二:尾插法

这个方法的思路是这样的,我们重新定义一个链表,这个链表使用两个结点指针来控制,一个是头节点newhead,另一个是尾结点tail。一开始让他们都为空,即这个链表是空链表

然后我们在使用一个结点指针cur来遍历原来的链表,如果此处的值不是val,那就将这个结点尾插到新链表上。然后让尾结点向后走,cur结点也向后走。注意当第一个结点插入的时候,由于tail为空,所以特殊处理,直接赋值,然后使cur向后走即可

如果某处的值确实是val,那么就要设置一个新结点next去接收cur的下一个结点,然后释放cur。然后让tail的下一个结点赋值为cur。注意,这里还有一个特殊情况是,当题目所给的链表全要被删除的时候,由于tail为空,所以无法让tail的下一个结点赋值为cur。这里我们直接使用一个if排除掉这种情况即可

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){struct ListNode* newhead=NULL;struct ListNode* tail=NULL;struct ListNode* cur=head;while(cur!=NULL){if(cur->val!=val){if(newhead==NULL){newhead=cur;tail=cur;cur=cur->next;}else {tail->next=cur;tail=cur;cur=cur->next;}}else {struct ListNode* next=cur->next;free(cur);cur=next;if(tail!=NULL)tail->next=cur;}}return newhead;
}

二、链表的中间结点

题目描述:力扣

解一:

对于这道题,我们最容易想到的思路就是,先遍历一遍,得到链表的长度,然后除2,就能得到要到达中间结点的长度。然后再一次遍历就能解出

解二:快慢指针

对于这道题,还有一种比较好的方法就是,一开始定义两个结点指针,然后一个一次走一步,另外一个一次走两步,如此一来,慢的那个指针恰好就是中间结点。具体代码如下

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

三、链表中倒数第k个结点

题目链接:链表中倒数第k个结点_牛客题霸_牛客网

对于这道题目,与第二题十分相似,也是采用快慢指针的方式,不过不同的是,这里的快慢是距离的快慢,而上一道题是速度的快慢。

这道题目的关键就是,fast应该要先走k步,然后两者再一起走,当fast为空的时候,返回慢指针即可

如果fast先走k-1步,那么fast的下一个指针为空的时候,返回慢指针

注意如果链表为空,那么直接返回空即可,如果k大于链表长度,那么就直接返回空就可以,这就意味着,fast先走的时候,每走一步都要判断一下此时fast是否为空

/*** struct ListNode {*	int val;*	struct ListNode *next;* };*//*** * @param pListHead ListNode类 * @param k int整型 * @return ListNode类*/
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) 
{if(pListHead==NULL){return NULL;}// write code herestruct ListNode* fast = pListHead;struct ListNode* slow = pListHead;while(k--){if(fast!=NULL)fast=fast->next;elsereturn NULL;}while(fast){fast=fast->next;slow=slow->next;}return slow;
}

四、反转链表

题目描述:力扣

解一:直接改变指向

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* reverseList(struct ListNode* head){struct ListNode* prev=NULL;struct ListNode* cur=head;while(cur!=NULL){struct ListNode* next=cur->next;cur->next=prev;prev=cur;cur=next;}return prev;
}

如上代码所示,这是最容易想到的方法,直接改变指向,我们先定义三个指针,prev,cur和next,然后使用循环依次改变指向即可

解二:头插法

这个的思路跟前面的尾插法类似, 我们可以定义一个新的链表newhead,然后将原来链表的头一个一个取出来进行头插即可

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* reverseList(struct ListNode* head){struct ListNode* newhead=NULL;struct ListNode* cur=head;while(cur!=NULL){struct ListNode* next=cur->next;cur->next=newhead;newhead=cur;cur=next;}return newhead;
}

五、合并两个有序链表

题目描述:力扣

解一:尾插法

这道题目也是比较适合尾插,如果第一个链表的数据小于第二个链表的数据,那么就尾插第一个,然后cur向后移动,反之也是一样的,代码如下

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1==NULL){return list2;}if(list2==NULL){return list1;}struct ListNode* cur1=list1;struct ListNode* cur2=list2;struct ListNode* newhead=NULL;struct ListNode* tail=NULL;while(cur1&&cur2){if((cur1->val)<(cur2->val)){if(newhead==NULL){newhead=tail=list1;cur1=cur1->next;}else{tail->next=cur1;tail=cur1;cur1=cur1->next;}}else{if(newhead==NULL){newhead=tail=list2;cur2=cur2->next;}else{tail->next=cur2;tail=cur2;cur2=cur2->next;}}}if(cur1==NULL){tail->next=cur2;}else{tail->next=cur1;}return newhead;
}

解二:哨兵位

我们可以先创建一个哨兵位,然后利用这个哨兵位去修改解法一的代码。可以一定程度上优化代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if(list1==NULL){return list2;}if(list2==NULL){return list1;}struct ListNode* cur1=list1;struct ListNode* cur2=list2;struct ListNode* guard=NULL;struct ListNode* tail=NULL;guard=tail=(struct ListNode*)malloc(sizeof(struct ListNode));tail->next=NULL;while(cur1&&cur2){if((cur1->val)<(cur2->val)){tail->next=cur1;tail=cur1;cur1=cur1->next;}else{tail->next=cur2;tail=cur2;cur2=cur2->next;}}if(cur1==NULL){tail->next=cur2;}else{tail->next=cur1;}struct ListNode* head=guard->next;free(guard);guard=NULL;return head;
}

六、分割链表

题目链接:力扣

解一:尾插法(不带哨兵位)

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* partition(struct ListNode* head, int x){struct ListNode* lesshead=NULL;struct ListNode* lesstail=NULL;struct ListNode* greaterhead=NULL;struct ListNode* greatertail=NULL;struct ListNode* cur=head;while(cur!=NULL){if(cur->val<x){//尾插到较小的链表if(lesshead==NULL){lesshead=lesstail=cur;cur=cur->next;}else{lesstail->next=cur;lesstail=cur;cur=cur->next;}}else{if(greaterhead==NULL){greaterhead=greatertail=cur;cur=cur->next;}else{greatertail->next=cur;greatertail=cur;cur=cur->next;         }}}if(lesshead==NULL){return greaterhead;}if(greaterhead==NULL){return lesshead;}lesstail->next=greaterhead;greatertail->next=NULL;return lesshead;
}

对于这道题,依旧采取尾插法,既然要使用尾插法,那么势必需要构建两个新链表

题目要求是将所有小于x 的值全部放在前面,且不改变顺序

那么可以使用一个链表去管理小于x 的值。同样由于是尾插,需要使用头尾两个结点来管理

然后使用另外一个链表去管理大于等于x的值,也需要使用头尾两个结点去管理

由于是尾插,那么势必涉及到链表为空,这里的链表为空状态比较复杂。如果采用哨兵位的话,确实可以避免分情况讨论了。但是这里我们选择迎难而上,不采用哨兵位的解法

既然不采用哨兵位了,那么我们现在来分析这道题,首先是定义四个结点指针,然后我们去遍历原来的链表,如果小于x,尾插到较小链表,这里要注意,如果链表为空,需要分情况讨论。

如果大于等于x,尾插到较大链表,这里也要注意,如果链表为空,也需要分情况讨论

当尾插全部完成以后。

我们还需要进行分情况讨论,如果较小链表为空,那么直接返回较大链表即可,如果较大链表为空,返回较小链表即可。

然后我们链接较小链表和较大链表,最后要注意较大链表的尾部一定要置空,否则由于尾插可能会导致出现环。代码如上所示

解二:尾插法(带哨兵位)

前面我们已经知道了不带哨兵位的方法,我们发现,分情况讨论特别繁琐。对于尾插法,如果使用哨兵位,就可以直接无视掉所有的分情况讨论。而大体思路却不会变化太多,下面是代码。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     struct ListNode *next;* };*/struct ListNode* partition(struct ListNode* head, int x){struct ListNode* lessGuard=NULL;struct ListNode* lesstail=NULL;struct ListNode* greaterGuard=NULL;struct ListNode* greatertail=NULL;lessGuard=lesstail=(struct ListNode*)malloc(sizeof(struct ListNode));greaterGuard=greatertail=(struct ListNode*)malloc(sizeof(struct ListNode));greatertail->next=NULL;lesstail->next=NULL;struct ListNode* cur=head;while(cur!=NULL){if(cur->val<x){lesstail->next=cur;lesstail=cur;cur=cur->next;}else{greatertail->next=cur;greatertail=cur;cur=cur->next;         }}lesstail->next=greaterGuard->next;greatertail->next=NULL;head=lessGuard->next;free(lessGuard);free(greaterGuard);lessGuard=greaterGuard=NULL;return head;
}

这里我们有一点需要特别注意,一定要让greatertail->next置为空,否则会陷入死循环,这也是使用哨兵位就需要做的一些细节,一旦使用哨兵位,一定要注意一些细节


本小节内容就到这里了,欲知后事请看下节

如果对你有帮助的话,一定要点赞加收藏哦!!!

相关文章:

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

目录 一、移除链表元素 二、链表的中间结点 三、链表中倒数第k个结点 四、反转链表 五、合并两个有序链表 六、分割链表 一、移除链表元素 题目描述&#xff1a;力扣 法一&#xff1a;直接循环依次判断 对于这个题目&#xff0c;我们最容易想到的一种思路就是&#xff0c…...

SAP BPC简介

BPC是SAP在financial application领域主推的产品&#xff0c;由于从原有产品线发展而来&#xff0c;产品本身有两个版本&#xff0c;分别是基于MS OLAP平台和Netweaver OLAP平台。 整个系统分为.net前台和abap后台。由于abap端的数据结构与.net数据结构的差异&#xff0c;所以没…...

Linux网络概述

写咋前面 今天,我们需要初步的认识一下Linux中网络的基本原理,只有大家对这个有一个初步的认识,后面我们学习起来才会更加的简单容易.计算机语言知识那么多,但是Linux不是.面试时,面试官总是会有问题难住你,我们后面需要看看书,这一点非常重要.我们现在谈的是脉络,.是框架.这些…...

Mybatis --- 获取参数值和查询功能

一、MyBatis的增删改查 1.1、新增 <!--int insertUser();--> <insert id"insertUser">insert into t_user values(null,admin,123456,23,男) </insert> 1.2、删除 <!--int deleteUser();--> <delete id"deleteUser">dele…...

【C++】C++入门,你必须要知道的知识

1.C关键字 &#x1f525;前言&#xff1a; C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助。今天的主要目标&#xff1a; 1️⃣ 补充C语言语法的不足&…...

spring(七):事务操作

spring&#xff08;七&#xff09;&#xff1a;事务操作前言一、什么是事务二、事务四个特性&#xff08;ACID&#xff09;三、事务操作&#xff08;搭建事务操作环境&#xff09;四、事务操作&#xff08;Spring 事务管理介绍&#xff09;五、事务操作&#xff08;注解声明式事…...

Word怎么转换成PDF文件格式?思路提供

PDF是一种通用的文件格式&#xff0c;它可以在不同操作系统和设备上保持一致的显示效果。在日常工作或学习中&#xff0c;我们常常需要将Word文档转换为PDF格式&#xff0c;以便更好地进行分享、存档或打印&#xff0c;毕竟Word文档则往往会因为不同版本的软件或者字体等原因而…...

HCIE-Cloud Computing LAB备考第二步:逐题攻破--第五题:规划--根据网络平面规划表,完成ensp中接入交换机SW1/2的配置

我是第五题规划题目的要求之一,需要从这里跳转过来,没看过题目的彭友,可以先跳转过去哈 解题:根据网络平面规划表,在两台交换机上对应的端口表填写服务器的网口号,完成ensp中接入交换机SW1/2的配置 答案 完成交换机端口表 第一:心中划分好“服务器接口表”,考试不需…...

【无标题】Perforce研讨会回顾 | Helix Core在芯片行业的应用实例:芯片项目的版本控制、持续集成及自动化

2023年2月28日&#xff0c;龙智联合全球领先的数字资产管理和DevSecOps工具厂商Perforce共同举办Perforce on Tour网络研讨会——“赋能‘大’研发&#xff0c;助力‘快’交付”。 研讨会上&#xff0c;在芯片行业有15年经验的Perforce Helix Core深度用户——何刚了带来精彩演…...

AdamW 优化器

Adam 优化器于 2014 年推出&#xff0c;其思想&#xff1a;既然知道某些参数移动得更快、更远&#xff0c;则每个参数不需要遵循相同的学习率&#xff0c;因为最近梯度的平方代表每一个权重可以得到多少信号&#xff0c;可以除以这个&#xff0c;确保即使是最迟钝的权重也有机会…...

手把手教你基于HTML、CSS搭建我的相册(上)

The sand accumulates to form a pagoda写在前面HTML是什么&#xff1f;CSS是什么&#xff1f;demo搭建写在最后写在前面 其实有过一些粉丝咨询前端该从什么开始学&#xff0c;那当然是我们的前端基础三件套开始学起&#xff0c;HTML、CSS、javaScript&#xff0c;前端的大部分…...

基于Redis实现的延时队列

基于Redis实现的延时队列 针对于Redis实现延时队列有两种实现方式&#xff1a; 使用zset实现实现的延时队列 借助redis zset来实现延时队列&#xff0c;具体的实现代码很简单&#xff0c;就是从zset中取出score小于当前时间戳的数据 import cn.hutool.json.JSONUtil; impor…...

(3.16——3.19)本周后半段总结

周四&#xff08;3.16&#xff09; 1.封装了TitleTip组件&#xff0c;并写了博客记录 http://t.csdn.cn/DAY4chttp://t.csdn.cn/DAY4c2.菜单跳转配置完毕&#xff0c;进行了一些页面的细节样式修改 3.基本写完了ServerSideEncryption页面&#xff0c;十一点多剩最后一点交互的…...

C++ 基础: cin和getline() 有啥区别?

所谓温故而知新&#xff0c;所以时不时会回头来看看我们最最基础的知识。 获取标准键盘输入的方法有多种。以C语言来说&#xff0c;最常用的就是cin 和geline() 。那么它们之间有什么区别呢&#xff0c;我们总结一下。 一、cin和geline的异同点 在 C 中&#xff0c;cin 和 ge…...

在使用fastjson中遇到的问题

一、在使用fastjson中遇到的问题 导论&#xff1a;最近在写一个JavaFx项目的时候使用到了fastjson作为处理json数据的依赖。在其它非JavaFx项目中也使用到了相同版本的fastjson&#xff0c;但是可以正常运行&#xff0c;而在JavaFx项目中却报异常&#xff0c;刚开始以为是我的依…...

C++造轮子飙车现场之无锁、有锁环形队列实现

先看带锁的实现。 带锁版本 circular_queue.h // 头文件防卫 #ifndef CIRCULAR_QUEUE_H #define CIRCULAR_QUEUE_H#include <mutex> // 互斥量 #include <condition_variable> // 条件变量template <typename T> class CircularQueue { public:// 构造函数…...

Spring Profiles and @Profile

1. Overview In this tutorial, we’ll focus on introducing Profiles in Spring. Profiles are a core feature of the framework — allowing us to map our beans to different profiles — for example, dev, test, and prod. We can then activate different profiles…...

数据分析-数据探索

文章目录前言主要内容总结更多宝藏前言 &#x1f60e;&#x1f973;&#x1f60e;&#x1f920;&#x1f62e;&#x1f916;&#x1f648;&#x1f4ad;&#x1f373;&#x1f371; 随着大数据和人工智能技术的不断发展&#xff0c;数据分析已经成为了一种非常重要的技能和工…...

7个最受欢迎的Python库,大大提高开发效率

当第三方库可以帮我们完成需求时&#xff0c;就不要重复造轮子了 整理了GitHub上7个最受好评的Python库&#xff0c;将在你的开发之旅中提供帮助 PySnooper 很多时候时间都花在了Debug上&#xff0c;大多数人呢会在出错位置的附近使用print&#xff0c;打印某些变量的值 这个…...

Intellij IDEA 中调试 maven 插件

Intellij IDEA 中调试 maven 插件话痨一下步骤1. classfinal-demo 项目部分2. ClassFinal 部分参考资料话痨一下 目前有两个项目&#xff1a; ClassFinal 是一款java class文件安全加密工具。classfinal-demo 是我建的一个Demo&#xff0c;用来测试ClassFinal的加密效果。 目…...

Java全栈知识(1)缓存池

我们先看这么一道题 Integer x new Integer(123); Integer y new Integer(123); System.out.println(x y); // false Integer z 123; Integer k 123; System.out.println(z k); // true Integer a 200; Integer b 200; System.out.println(z k); //false 我们…...

网络安全的特性

0x00 前言 网络安全的特性包括&#xff0c;机密性&#xff0c;完整性&#xff0c;可用性&#xff0c;真实性和不可否认性。详细的内容可以参考如下的内容。 Xmind资源请下载~ 0x01 机密性 机密性&#xff08;Confidentiality&#xff09; 意味着阻止未经授权的实体&#x…...

YOLOv8 多目标跟踪

文章大纲 简介环境搭建代码样例跟踪原理代码分析原始老版实现新版本封装代码实现追踪与计数奇奇怪怪错误汇总lap 安装过程报错推理过程报错参考文献与学习路径简介 使用yolov8 做多目标跟踪 文档地址: https://docs.ultralytics.com/modes/track/https://github.com/ultralyt…...

Gitee搭建个人博客(Beautiful Jekyll)

目录一、引言二、博客模板选型 - Jekyll三、安装Jekyll环境3.1 安装Ruby3.2 安装Jekyll3.3 下载Jekyll主题四、搭建我的Gitee博客4.1 选择主题 - Beautiful Jekyll4.2 创建Gitee账号同名代码库4.3 写博客4.4 开通Gitee Pages服务五、对Beautifu Jekyll的相关优化一、引言 之前…...

图形视图框架 事件处理(item)

在图形界面框架中的事件都是先由视图进行接收&#xff0c;然后传递给场景&#xff0c;再由场景传递给图形项。通过键盘处理的话&#xff0c;需要设置焦点&#xff0c;在QGraphicsScene中使用setFoucesItem&#xff08;&#xff09;函数可以设置焦点&#xff0c;或者图形项使用s…...

PTA第六章作业详解

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;夏目的作业 &#x1f4ac;总结&#xff1a;希望你看完之后&am…...

Java课程设计项目--音乐视频网站系统

一、功能介绍 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对音乐方面的要求也在不断提高&#xff0c;听歌的人数更是不断增加&#xff0c;使得音乐网站的设计的开发成为必需而且紧迫的事情。音乐网站的设计主…...

FPGA可以转IC设计吗?需要学习哪些技能?

曾经在知乎上看到一个回答“入职做FPGA&#xff0c;后续是否还可以转数字IC设计&#xff1f;” 从下面图内薪资就可以对比出来&#xff0c;对比FPGA的行业薪资水平&#xff0c;IC行业中的一些基础性岗位薪资比很多FPGA大多数岗位薪资都要高。 除了薪资之外更多FPGA转IC设计的有…...

初探Gradle

目录一.概述二.优点三.安装与配置1. 官网下载2. 配置环境变量3. 检验4. 配置国内镜像(可选)5. IDEA配置三.工程结构四.生命周期1.Initialization阶段2.Configuration阶段3.Execution阶段五.Task六.常用任务指令七.引入依赖1.本地依赖2.项目依赖3.直接依赖八.依赖类型九.插件十.…...

国产数据库介绍

人大金仓 Kingbase 北京人大金仓信息技术股份有限公司于1999年由中共人民大学专家创立&#xff0c;自成立以来&#xff0c;始终立足自主研发&#xff0c;专注数据管理领域&#xff0c;先后承担了国家“863”、“核高基”等重大专项&#xff0c;研发出了具有国际先进水平的大型…...