链表经典面试题【典中典】
💯💯💯链表经典面试题❗❗❗炒鸡经典,本篇带有图文解析,建议动手刷几遍。
- 🟥1.反转链表
- 🟧2.合并两个有序链表
- 🟨3.链表分割
- 🟩4.链表的回文结构
- 🟦5.相交链表
🟥1.反转链表
方法一:利用双指针逆转方向
将各个结点的连接方向都倒过来,2结点指向1结点,3结点指向2结点等,我们只要将让每个结点的next指向前一个结点的地址
双指针–将指针指向前面,最后一个变成头。两个指针,一前一后
注意点:
- 单链表不能往前走
- 第一个指针首先指向NULL ,第二个指针在后面,这两个指针用来转变指向
不过这时第二个指针的后面的地址无法知道,这时需要第三个指针用来记录第二个指针后面的结点的地址。 - 当第三个指针往后走的时候可能为NULL,要注意下
代码如下:
struct ListNode* reverseList(struct ListNode* head)
{if(head==NULL)//如果链表为空则直接返回NULLreturn NULL;struct ListNode* prev = NULL;//与cur搭配,记录前面的,一开始为NULLstruct ListNode* cur = head;//一开始为第一个结点,所以将head传给cur,让cur遍历链表struct ListNode* next =cur->next;//next用来记录cur后面结点的地址while (cur)//当cur不为NULL时进行{//方向逆转cur->next = prev;//将每一个结点的next指向前一个结点的地址//迭代--让我们的条件往后执行prev = cur;//让pre跑到cur的位置上来cur = next;//让cur跑到next的位置上来if (next)//这里next可能会跑着跑着为NULL了,所以需要判断下next = next->next;//往后跑}return prev;//最后尾就是头了,将尾传回去
}
方法2:利用头插原理
取原结点头插到新链表
原本是1 2 3 4 5
我们只要将每个结点拿下来,然后头插到一个新链表上就会变成5 4 3 2 1了
代码如下:
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur = head;//利用cur进行遍历,不要用形参headstruct ListNode* newnode = NULL;//首先创建一个新的空链表while (cur)//当cur为空时结束{//首先要记录下来cur后面结点的地址struct ListNode* next = cur->next;//头插cur->next = newnode;//将取下来的结点头插到新链表中newnode = cur;//更新头指针cur = next;//cur要往后走}return newnode;//返回新链表的头指针
}
🟧2.合并两个有序链表
这种题目在数组中也有类似的,原理也是一样,合并两个有序数组
也就是依次比较取小的结点尾插,最后如果比较完还有结点直接尾插到没有结点的后面去。
注意点:
-
当第一次尾插到一个新链表时,我们需要的 是进行直接赋值,将第一个结点直接赋值给新链表的头指针而不能进行尾插
-
当第一次以后才可以进行真正的尾插
-
当其中有一个或两个链表为空链表的话,那么直接跳过比较环节,而进入将还有结点的直接尾插到没有结点的后面去
这时因为没有结点的链表为NULL,所以就无法访问它的next也就无法将它和另一个链表链接起来。所以这时我们需要在前面讨论一下,当其中有一个链表为NULL,则直接返回另外一个链表。
方法1:
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){if (list1 == NULL)//当链表1为空则直接返回链表2return list2;if (list2 == NULL)//当链表2为空则直接返回链表1return list1;struct ListNode* cur1 = list1, * cur2 = list2;//利用cur1,cur2遍历链表struct ListNode* head = NULL, * tail = NULL;//head,用来传回,tail用来找尾while (cur1 && cur2)//当其中有一个结束就结束{if (cur1->val < cur2->val)//哪个小就尾插谁{//将小的尾插//但一开始为空第一步就是赋值if (head == NULL){head = tail = cur1;}//接下来才是真正的尾插else{tail->next = cur1;//将cur1链接在tail的后面tail = tail->next;//tail要往后找尾,这样就不需要每次从开始进行找尾了}cur1 = cur1->next;//cur往后走}else {//将小的尾插//但一开始为空第一步就是赋值if (head == NULL){head = tail = cur2;}//接下来才是真正的尾插else{tail->next = cur2;tail = tail->next;}cur2 = cur2->next;}}//将长的链表指针尾插到tail后面//不过还有一种情况就是plist为空cur1为空,则tail还是NULL,这种情况需要讨论if (cur1){tail->next = cur1;}else{tail->next = cur2;}return head;//返回head
}
还有一种方法可以避免讨论tail的next是否为空,和第一次尾插需要赋值等问题。
我们可以利用带有头哨兵卫的头结点。
这样tail永远不可能为空了,就不需要讨论那么多为空的情况了。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* cur1 = list1, * cur2 = list2;struct ListNode* head =NULL,* tail = NULL;struct ListNode* guard = tail = (struct ListNode*)malloc(sizeof(struct ListNode));//动态开辟一个哨兵头结点,让tail一开始就指向头结点,这样tail就永远不会为NULL了while (cur1 && cur2)//当其中有i一个结束就结束{if (cur1->val < cur2->val){//将小的尾插//不需要进行讨论第一个头节点为NULL的情况了,直接进行尾插tail->next = cur1;tail = tail->next;cur1 = cur1->next;}else{//将小的尾插tail->next = cur2;tail = tail->next;cur2 = cur2->next;}}//将长的链表指针尾插到tail后面//如果没有哨兵头,plist为空cur1为空,则tail还是NULL,这种情况就需要讨论//但先走有了哨兵头结点,tail不可能为空,直接让tail的next与另一个链表剩余的结点链接起来if (cur1){tail->next = cur1;}else{tail->next = cur2;}head=guard->next;//将第一个结点的地址记录下来free(guard);//释放guardreturn head;
}
🟨3.链表分割
要求将所有小于x的结点排在其他结点之前,且不能改变原来的数据顺序
我们可以这样做:
- 将小于x的结点插入到一个链表中
- 将大于x的结点插入到一个链表中
- 最后将两个链表链接起来。
不过这里我们最好使用带有哨兵头的链表,这样可以减少进行对NULL的讨论不然会很麻烦
比如如果数据全是 6 6 6 6 6 而x为5
则less链表为空,那么将两个链表链接起来有会出问题,ltail都为NULL还有next吗?,所以我们使用带有哨兵卫的链表能很好的减少这种讨论。
class Partition {
public:ListNode* partition(ListNode* pHead, int x) {ListNode* Lguard,*Gguard,*ltail,*gtail;Lguard=ltail=(ListNode*)malloc(sizeof(ListNode));//less链表的哨兵头Gguard=gtail=(ListNode*)malloc(sizeof(ListNode));//greater链表的哨兵头ltail->next=NULL;//一开始要置NULLgtail->next=NULL;ListNode* cur=pHead;//利用cur进行遍历while(cur){if(cur->val<x)//如果小于x就尾插到less的链表中{ltail->next=cur;//将小的数据尾插到ltail的后面ltail=ltail->next;//找尾}else {gtail->next=cur;//将大的数据尾插到gtail后面gtail=gtail->next;}cur=cur->next;//每次cur也要往后走}ltail->next=Gguard->next;//让两个链表链接起来gtail->next=NULL;//想一想这一步是为什么呢?因为最后7的next还链接着2呀,这样就造成回环了。所以需要将gtail的next置为NULLpHead=Lguard->next;//第一个结点free(Lguard);//释放free(Gguard);//释放return pHead;//返回第一个结点地址}
};
🟩4.链表的回文结构
我们看到链表时有时就会想转空子,想先使用数组来存储链表的数据,然后再进行判断,我们在知道链表长度的前提下理论上是可以的,但最好不要这样做,如果不知道长度,我们还需要动态增容等,所以要抛弃这个想法。
那怎么判断回文结构呢?
回文结构也就是对称,从中间对称,左边与右边对称,如果我们把右边逆转下,那么右边就和左边一样了。所以我们就可以根据左边和右边是否一样进行判断了
- 首先我们需要找到中间结点
- 逆转中间结点以后的结点
- 从逆转开始的位置与开头进行比较
逆转链表,查找链表的中间结点我都已经写过了,这里直接就复制过来。
《找链表的中间结点》
《反转链表》
class PalindromeList {
public:
struct ListNode* middleNode(struct ListNode* head)//找链表中间结点
{struct ListNode *fast,*slow;fast=slow=head;while(fast!=NULL&&fast->next!=NULL){slow=slow->next;fast=fast->next->next;}return slow;}
struct ListNode* reverseList(struct ListNode* head)//反转链表
{
struct ListNode* cur = head;struct ListNode* newnode = NULL;while (cur){//首先要记录下来cur后面结点的地址struct ListNode* next = cur->next;//头插cur->next = newnode;newnode = cur;//更新头指针cur = next;//cur要往后走}return newnode;
}bool chkPalindrome(ListNode* phead){ListNode *mid= middleNode(phead);//找中间结点ListNode *rhead = reverseList(mid);//逆转中间结点以后//比较链表前面数据与逆转后的数据while(rhead)//当逆转后的结点走到NULL时结束{if(rhead->val!=phead->val)return false;//当有一个不等于就然后falsephead=phead->next;rhead=rhead->next;}return true;//走到这说明都相等}
};
🟦5.相交链表
怎么判断两个链表是否相交呢?
怎么返回这个相交结点呢?
传统思想可能会让链表A中每个结点的地址与链表B中结点的地址都比较一下,当第一次比较相同时,就是相交结点,不过这种方法的时间复杂度为O(N^2)了,不好,有没有让时间复杂度为O(N)的呢?
好的让我来告诉你吧:
如果两个链表是相交的,那么它们的尾结点的地址一定相同,如果尾结点地址不相同那么肯定不相交。
接着让长的链表先走长度差步,然后两个链表再一起走,当两个链表结点地址比较相同时就是相同结点的位置。
所以
- 求出两个链表的长度,判断是否相交。
- 让长度长的链表先走长度差步,然后一起走
- 两个链表结点地址相比,第一次相同的为相交结点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {struct ListNode *cur1=headA,*cur2=headB;//用cur1遍历链表A,用cur2遍历链表2int lena=0;int lenb=0;while(cur1->next)//记录链表A的长度{cur1=cur1->next;++lena;}while(cur2->next)//记录链表B的长度{cur2=cur2->next;++lenb;}if(cur1!=cur2)//如果链表尾结点不相同那么肯定不相交return NULL;int gap=abs(lena-lenb);//长度差,但我们不知道哪个链表长struct ListNode *longlist=headA,*shortlist=headB;if(lenb>lena)//所以我们需要讨论下{longlist=headB,shortlist=headA;}while(gap--)//让长的链表先走长度差步{longlist=longlist->next;}while(longlist!=shortlist)//然后两个链表一起走,当没有结点地址相同时则一起走{longlist=longlist->next;shortlist=shortlist->next;}return longlist;//最后如果有相同的就返回
}
相关文章:
链表经典面试题【典中典】
💯💯💯链表经典面试题❗❗❗炒鸡经典,本篇带有图文解析,建议动手刷几遍。🟥1.反转链表🟧2.合并两个有序链表🟨3.链表分割🟩4.链表的回文结构🟦5.相交链表&…...
Java泛型深入
一. 泛型的概述和优势 泛型概述 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。泛型的格式:<数据类型>,注意:泛型只能支持引用数据类型。集合体系的全部接口和实现类都是…...
体验Linux USB 驱动
目录 一、USB OTG 二、I.MX6ULL USB 接口简介 硬件原理图 1、USB HUB 原理图 2 、USB OTG 原理图 三、使能驱动 1、打开 HID 驱动 2、 使能 USB 键盘和鼠标驱动 3 、使能 Linux 内核中的 SCSI 协议 4、使能 U 盘驱动 四、测试u盘 五、 Linux 内核自带 USB OTG USB 是…...
servlet 中的ServletConfig与servletContext
ServletConfig对象:servlet配置对象,主要把servlet的初始化参数封装到这个对象中。 一个网站中可能会存在多个servletConfig对象,一个servletConfig对象就封装了一个servlet的配置信息。 可以在web.xml中通过<init-param></init-p…...
Hadoop3.1.3单机(伪分布式配置)
参考:林子雨老师网站博客 Hadoop安装搭建伪分布式教程(全面)吐血整理 环境 Vmare12 Ubuntu16.04 创建Hadoop用户 若安装Ubuntu不是用的“hadoop”用户,则需要增加一个名为"hadoop"的用户 直接快捷键ctrlaltt或者点…...
HBase---浅谈HBase原理
浅谈HBase原理 文章目录浅谈HBase原理HBase定义HBase逻辑结构HBase物理存储结构TimeStampType数据模型NaneSpaceRegionRowColumnTineStampCellHBase架构MasterMaster 架构Meta 表格介绍Region ServerRegionServer 架构MemStoreWALBlockCacheZookeeperHDFSHBase写数据流程HBase读…...
学习笔记四:dockerfile
Dockerfile概述dockerfile语法详解FROMMAINTAINERRUN:指定在当前镜像构建过程中要运行的命令EXPOSE指令CMDENTERYPOINTCOPYADDVOLUMEWORKDIRENVUSERONBUILDLABELHEALTHCHECKARG概述 Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜…...
微服务里的小问题
1.微服务为什么设置不同的namespace 为了实现三种服务三种情况下的隔离。 2.为什么要用nginx为naocos集群结点做负载均衡? 2.1 正向代理 就像我们访问外网需要一个代理。 2.2 反向代理 我们不需要访问真实的ip,只需要访问 这个服务的代理服务器即可&a…...
数据库之基本功:Where 中常用运算符
1. 运算符及优先级 ( )优先级最高 SQL> show user; USER is "SCOTT" SQL> select ename, job, sal, comm from emp where jobSALESMAN OR jobPRESIDENT and sal> 1500;ENAME JOB SAL COMM …...
浅谈 Nodejs原型链污染
一直在做php的题目,对其它语言做的很少。刚好在西湖论剑2022复现时,遇到了一道原型链污染的题目,借此机会开始简单学习一下 Nodejs的洞 p🐂讲解的十分清楚,因此下面举例子就直接用p🐂的例子进行解释了 目…...
Linux系统安装Docker
目录 Linux系统安装Docker 1、如果之前安装过旧版本的Docker,可以使用下面命令卸载 2、安装docker 3、启动docker 4、配置镜像加速 Linux系统安装Docker 前提:Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10࿰…...
MCP2515国产替代DP2515带有SPI 接口的独立CAN 控制器
DP2515是一款独立控制器局域网络(Controller AreaNetwork, CAN)协议控制器,完全支持CAN V2.0B 技术规范。该器件能发送和接收标准和扩展数据帧以及远程帧。DP2515自带的两个验收屏蔽寄存器和六个验收滤波寄存器可以过滤掉不想要的…...
【Kubernetes】第二十篇 - k8s 污点和容忍度
一,前言 上一篇,介绍了 k8s ConfigMap 管理服务环境变量; 本篇,介绍 k8s 污点和容忍度; 二,污点与容忍度介绍 通过污点和容忍度配置可以干预 Pod 部署到特定的节点; 比如: 不想让…...
60% 程序员大呼:我要远程办公!
近几年数字化的普及,白领们从挤地铁、打卡、开会、写日报转变成“早上9点视频会议”,企业的办公场所也从写字楼、会议室、工位变成了手机、电脑中的线上会议室,远程办公已经成为一种流行的办公形式。《财富》杂志发现,75%的员工表…...
jmeter+ant+jenkins接口自动化测试框架
大致思路:Jmeter可以做接口测试,也能做压力测试,而且是开源软件;Ant是基与java的构建工具,完成脚本执行并收集结果生成报告,可以跨平台,Jenkins是持续集成工具。将这三者结合起来可以搭建一套We…...
【protoc自定义插件】「go语言」实现rpc的服务映射成http的服务,protoc生成gin的插件,(详解实现原理及过程)
文章目录前言一、工程实践中如何更好的使用proto文件?二、protoc命令如何查询依赖的proto文件以及执行原理1. protoc命令如何查询依赖的proto文件2. protoc执行的插件加载原理是什么?3. proto文件中的package和go_package的作用三、protoc插件开发原理体…...
【C语言】3天速刷C语言(语句、函数)
语句分支语句if语句if语句语法结构语法结构: if(表达式)语句; if(表达式)语句1; else语句2; //多分支 if(表达式1)语句1; else if(表达式2)语句2; else语句3;表达式如果成立,则执行,不成立则弹出。switch语句语法结构:switch(…...
Linux系统中指针的详细分析与操作
文章目录 一、指针 二、指针的初始化 三、指针的运算 四、指针与数组 五、指针与字符串 六、函数指针 七、NULL 指针 八、对复杂指针的解释 C 语言指针真正精髓的地方在于指针可以进行加减法,这一点极大的提升了程序的对指针使用的灵活性,同时也…...
工程(十一)——NUC11+D435i+VINS-FUSION+ESDF建图(github代码)
博主的合并代码gitgithub.com:huashu996/VINS-FUSION-ESDFmap.git一、D435i深度相机配置1.1 SDKROS参考我之前的博客,步骤和所遇见的问题已经写的很详细了https://blog.csdn.net/HUASHUDEYANJING/article/details/129323834?spm1001.2014.3001.55011.2 相机标定参数…...
第十四届蓝桥杯三月真题刷题训练——第 4 天
目录 题目 1 :九数算式_dfs回溯(全排列) 题目描述 运行限制 代码: 题目2:完全平方数 问题描述 输入格式 输出格式 样例输入 1 样例输出 1 样例输入 2 样例输出 2 评测用例规模与约定 运行限制 代码: 题目 1 &am…...
Hadoop 运行环境搭建(开发重点)
文章目录Hadoop 运行环境搭建(开发重点)一、安装JDK二、安装配置 Hadoop1、安装 hadoop2、hadoop 目录结构3、设置免密登录4、完全分布式模式(开发重点)1)分发jdk2)集群配置(1) 集群部署规划(2) 配置文件说…...
在社交媒体上行之有效的个人IP趋势
如果您认为无论是获得一份工作、建立一家企业还是推动个人职业发展,社交媒体都是帮助您实现目标的可靠工具,那么个人IP就是推动这一工具前进的燃料。个人IP反映了您是谁,您在所处领域的专业程度,以及您与他人的区别。社交媒体将有…...
Java网络编程
网络编程 什么是网络编程? 可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信) Java.net. 包下提供了网络编程的解决方案* 基本的通信架构 基本的通信架构有两种方式:CS架构(Client客户端/Se…...
PTA:L1-001 Hello World、L1-002 打印沙漏、L1-003 个位数统计(C++)
目录 L1-001 Hello World 问题描述: 实现代码: L1-002 打印沙漏 问题描述: 实现代码: 原理思路: L1-003 个位数统计 题目描述: 实现代码: 原理思路: 过于简单的就不再写题…...
构造HTTP请求
使用formform使用如下:<body><!-- 表单标签,允许用户和服务器之间交互数据 --><form action"https://www.sogou.com" method"get"><!-- 要求提交的数据以键值对的结构来组织 --><input type"text" name"stduent…...
转速/线速度/角速度计算FC
工业应用中很多设备控制离不开转速、线速度的计算,这篇博客给大家汇总整理。张力控制的开环闭环方法中也离不开转速和线速度的计算,详细内容请参看下面的文章链接: PLC张力控制(开环闭环算法分析)_plc的收卷张力控制系统_RXXW_Dor的博客-CSDN博客里工业控制张力控制无处不…...
学习笔记:Java并发编程(补)ThreadLocal
【尚硅谷】学习视频:https://www.bilibili.com/video/BV1ar4y1x727【黑马程序员】学习视频:https://www.bilibili.com/video/BV15b4y117RJ 参考书籍 《实战 JAVA 高并发程序设计》 葛一鸣 著《深入理解 JAVA 虚拟机 | JVM 高级特性与最佳实践》 周志明 著…...
HashMap底层实现原理及面试题
文章目录1. 常见的数据结构有三种结构1.1 各自数据结构的特点2. HashMap2.1 概述2.2 底层结构2.2.1 HashMa实现原理:2.2.1.1 map.put(k,v)实现原理2.2.1.2 map.get(k)实现原理2.2.1.3 resize源码2.2.2 HashMap常用的变量2.2.3 HashMap构造函数2.3 JDK1.8之前存在的问…...
【STM32】进阶(二):DMA+ADC实现模拟量检测
1、简述 DMA:Direct Memory Access,直接内存访问 ADC:Analog to Digital Converter,模数转换器,模拟信号转换成数字信号的电路(采样-量化-编码) 参考博客: STM32DMA功能详解 STM32…...
Lab2_Simple Shell_2020
Lab2: 实验目的:给xv6添加新的系统调用 并理解系统调用是如何工作的,并理解xv6内核的一些内部特征 实验准备: 阅读xv6的第2章以及第4章的4.3,4.3小节熟悉下面的源码 用户态相关的代码:user/user.h和user/usys.pl内核态相关的代…...
建设集团有限公司简介/佛山网站优化软件
--查看oracle的实例名,所在主机名,版本select INSTANCE_NAME,HOST_NAME,VERSION from v$instance;--查看oracle版本的详细信息,位数,其他组件信息select * from v$version--查看数据库服务器字符集,来源props$select *…...
西部数码备案域名购买/win7优化大师官网
为什么80%的码农都做不了架构师?>>> 解决intellij中sPRing boot工程 无法用mainapplication启动问题 一、spring boot 工程 从svn库导出到 intellij idea中 后用mainApplication中的main函数启动时会出现 Failed to introspect annotated methods on cl…...
一级a做爰片就在线看网站/uc浏览网页版进入
1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1783 Solved: 753[Submit][Status][Discuss]Description FJ打算带他的N(1 < N < 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”。在这场比赛中,每个参赛者都必须让他的奶…...
xampp安装wordpress/搜索引擎推广方法
4月1日,第十一届米粉节将正式拉开帷幕。安卓影像之王小米11 Ultra限时特惠1500元,今晚8点线上尾款支付和现货开售同步开启,到手价3999元,这也成为本届米粉节最值得入手的爆品之一。 本次小米11 Ultra限时特惠活动在小米官方全渠道…...
国内网如何看国外网站/友情链接的作用
【考试简介】全国专业技术人员计算机应用能力考试是一种计算机能力考试。全国职称计算机考试可以提高计算机和网络的普及应用程度,加强信息资源的开发和利用”的精神,落实国家加快信息化建设的要求,引导全国专业技术人员学习掌握计算机知识&a…...
怎么介绍自己做的电影网站/seo网站推广
360手机N4S配置怎么样?360手机N4S值得购买吗?360手机N4S有几个版本?各版本有什么区别?下面脚本之家的小编就带来了360手机N4S各版本区别对比评测,一起来看看吧。外观设计360手机N4S是360手机N4的升级版,但是…...