【Java数据结构】详解LinkedList与链表(二)
目录
1.❤️❤️前言~🥳🎉🎉🎉
2.反转一个单链表
3. 找到链表的中间节点
4.输入一个链表,输出该链表中倒数第k个结点。
5.合并两个有序链表
6.链表分割
7. 判定链表的回文结构
8.输入两个链表,找出它们的第一个公共结点。
9. 判断链表中是否有环
10.返回链表开始入环的第一个节点
11.总结
1.❤️❤️前言~🥳🎉🎉🎉
Hello, Hello~ 亲爱的朋友们👋👋,这里是E绵绵呀✍️✍️。
如果你喜欢这篇文章,请别吝啬你的点赞❤️❤️和收藏📖📖。如果你对我的内容感兴趣,记得关注我👀👀以便不错过每一篇精彩。
当然,如果在阅读中发现任何问题或疑问,我非常欢迎你在评论区留言指正🗨️🗨️。让我们共同努力,一起进步!
加油,一起CHIN UP!💪💪
🔗个人主页:E绵绵的博客
📚所属专栏:1. JAVA知识点专栏
深入探索JAVA的核心概念与技术细节
2.JAVA题目练习
实战演练,巩固JAVA编程技能
3.c语言知识点专栏
揭示c语言的底层逻辑与高级特性
4.c语言题目练习
挑战自我,提升c语言编程能力
📘 持续更新中,敬请期待❤️❤️
这篇文章我们将给大家带来一些单链表的面试题,都很有意思,来看一下吧。
2.反转一个单链表
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。
我们的解决方法是依次头插法:
最开始时我们需要将第一个节点的next值变为null,使其变成最后的节点,就产生了新的链表。而后依次将原始链表中的第二个节点,第三个节点直至最后一个节点头插到新链表中。
这样就翻转成功了
完整代码如下:
public void reverseList() {if(head==null)return;ListNode cur=head.next;ListNode prev;head.next=null;while(cur!=null){prev=cur.next;cur.next=head;head=cur;cur=prev;}}
这是该题的链接 : 翻转链表
3. 找到链表的中间节点
给你单链表的头结点
head
,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
该题的思路实现是设置两个引用:slow 慢引用 和 fast 快引用
fast 和 slow 同时从head开始遍历,但是fast一次走两步,slow一次只走一步,最后我们会发现当 fast遍历完成后 ,对应的slow正好是链表的中间节点或者第二个中间节点。
fast遍历完成的标志是fast.next=null或者fast=null
完整代码如下:
public ListNode middleNode(ListNode head) {ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;}return slow; }
该题链接:求链表中间结点
4.输入一个链表,输出该链表中倒数第k个结点。
该题有两种思路
第一种思路:
第二种思路:
所以我们采用第二种思路去做题,且我们还需要注意k的合法性。
整体代码如下:
public ListNode FindKthToTail(ListNode head,int k){ if(head==null){ return null; } ListNode fast = head; ListNode slow = head; //1.判断k值的合法性 if( k<=0 ){ System.out.println("k值不合法"); return null; } //2.让fast 提前走 k-1 步 while(k-1>0){ if(fast == null |l fast.next ==null){ System.out.println("k值不合法”); return null; } fast = fast.next; k--; } while(fast !=null && fast.next != null){ fast = fast.next;slow = slow.next; return slow; } }
该题题目已下架,无链接。
5.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
解题思路:
1.先创建一个新的链表
2.让cur1 和 cur2遍历两个链表,遇到的节点逐个比较,将值小的节点往新链表的末尾tail进行尾插
3.上述循环结束后,要判断有无链表还有剩余元素,把剩余的元素尾插到新链表的末尾。
完整代码如下:
public static ListNode mergeTwoLists(ListNode list1, ListNode list2){//将两个有序链表合并为一个有序链表ListNode head1=list1;ListNode head2=list2;ListNode head=new ListNode(-1);ListNode cur=head;while(head1!=null&&head2!=null){if(head1.value>head2.value){cur.next=head2;cur=cur.next;head2=head2.next;}else{cur.next=head1;cur=cur.next;head1=head1.next;}}while(head1!=null){cur.next=head1;cur=cur.next;head1=head1.next;}while(head2!=null){cur.next=head2;cur=cur.next;head2=head2.next;}return head.next;}
该题链接:合并两个有序链表
6.链表分割
现有一链表的头引用 pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
解题思路:
1.创建两个链表,一个链表尾插值小于x的节点,另一个链表中插值大于等于x的节点
2.遍历原链表,将链表中的节点往两个新链表中尾插
3.将两个链表拼接
但是这种思路仍然存在较大的问题,什么问题呢?
1.我们传入的x值比节点中val都大或者都小,那么存在一个问题就是有一个链表中的内容为空,那么按照上面的思路走时,必然会出现空指针异常的情况。
解决方法: 当第一个区间为空时,那么直接返回ca
2.最后一个节点分到小于x的区间,那么最后一个节点的next并不是null,所以此时我们必须手动将 cb.next=null; 预防最后一个节点的next不是null,从而报错。
完整代码如下:
public static ListNode partition(ListNode pHead, int x) {//给一定值x,该方法将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。if(pHead==null)return null;ListNode cur=pHead;ListNode sa=null;ListNode sb=null; //小于x的结点所在链表ListNode ca=null;ListNode cb=null; //大于x的结点所在链表while(cur!=null){if(cur.value<x){if(sa==null){sa=cur;sb=cur;cur=cur.next;}else{sb.next=cur;sb=cur;cur=cur.next;}}else{if(ca==null){ca=cur;cb=cur;cur=cur.next;}else{cb.next=cur;cb=cur;cur=cur.next;} }}//拼接两个链表if(sa==null)return ca;//如果不存在小于X的结点,则直接返回大于x的链表,否则按如下执行会报错if(ca!=null)cb.next=null;//将链表中的最后一个结点的next值变为null,防止其循环从而报错sb.next=ca;return sa;}
题目链接:链表分割_牛客题霸_牛客网
7. 判定链表的回文结构
解题思路实现:
1.找到链表的中间节点,找中间节点:采用快慢指针就行了
2.对链表的后半部分进行反转
3.将两个链表从前往后逐个节点进行比对,如果比对之后发现所有节点的值域都相同,则是回文链表,否则不是.
并且在循环时还需注意当链表为奇数或偶数时,判定循环结束的标志不同:
奇数是head==slow时结束
偶数是head.next=slow时结束
所以完整代码如下:
public static boolean checkPalindrome(ListNode A) {//判断链表是否为回文结构if(A==null||A.next==null)return true;ListNode slow=A;ListNode fast=A;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;}ListNode cur=slow.next;while(cur!=null){ListNode curnext=cur.next;cur.next=slow;slow=cur;cur=curnext;}ListNode head=A;while(head!=slow){if(head.value!=slow.value)return false;if(head.next==slow)return true;head=head.next;slow=slow.next;}return true;}
注意:在执行完该方法后链表结构会被破坏掉,之后如果还对该链表进行操作,结果会和我们预想的结果不一样。
该题链接:链表的回文结构_牛客题霸_牛客网
8.输入两个链表,找出它们的第一个公共结点。
给你两个单链表的头节点
headA
和headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回null
。
下面是两个节点相交的各类情况:
从上述链表相交的情况看出,两个单链表只要相交,从交点开始,到其后续所有的节点都是两个链表中公共的节点
检测两个链表是否相交:分别找到两个链表中的最后一个节点,然后检测这两个节点的地址是否相同即可:如果地址相同则相交,否则不相交
解题思路:
1.让较长的链表先走两个链表的差值步数
2.再让两个链表同时往后走,直到遇到地址相同的交点,没有则返回null
public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {//给你两个单链表的头节点 headA 和 headB ,找出并返回两个单链表相交的起始节点。if(headA==null||headB==null)return null;ListNode cur1=headA;ListNode cur2=headB;int length1=0;int length2=0;while(cur1!=null){length1++;cur1=cur1.next;}while(cur2!=null){length2++;cur2=cur2.next;}cur1=headA;cur2=headB;if(length1>length2){for(int i=0;i<length1-length2;i++){cur1=cur1.next;}}else{for(int i=0;i<length2-length1;i++){cur2=cur2.next;}}while(cur1!=null){if(cur1==cur2)return cur1;cur1=cur1.next;cur2=cur2.next;}return null;}
题目链接:找出两个链表的第一个公共节点
9. 判断链表中是否有环
给你一个链表的头节点
head
,判断链表中是否有环。
解题思路:
设计快慢指针去解决,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。
扩展问题:
1.为什么快指针每次走两步,慢指针走一步可以?
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现始终相遇不到的情况,因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
2.快指针一次走3步,走4步,...n步行吗?
假设:快指针每次走3步,满指针每次走一步,此时快指针肯定先进环,慢指针后来才进环。假设慢指针进环时候,快指针的位置如图所示:
此时按照上述方法来绕环移动,每次快指针走3步,慢指针走1步,它们是永远不会相遇的,因此不行。
只有快指针走2步,慢指针走一步才可以,因为每移动一次,它们之间的距离就缩小一步,无论如何都能相遇。所以我们在环问题中设置快慢指针,都是将快指针设置为一次两步,慢指针一次一步,这样当存在圈时无论如何都会相遇。
完整代码如下:
public static boolean hasCycle(ListNode head) {//给你一个链表的头节点 head ,判断链表中是否有环。if(head==null||head.next==null)//只有一个节点时默认绝对不存在环return false;ListNode slow=head;ListNode fast=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;if(slow==fast)return true;}return false;}
题目链接 :判断链表中是否有环
10.返回链表开始入环的第一个节点
给定一个链表的头节点
head
,返回链表开始入环的第一个节点。 如果链表无环,则返回null
。
解题思路:
设计一个慢指针,一个快指针,快指针一次两步,慢指针一次一步。使两指针相遇而后让一个指针从链表起始位置开始遍历链表,同时也让一个指针从相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
它们肯定会在入口点相遇的证明如下:
上图中的H为链表的起始点,E为环入口点,M为慢速指针相遇点,设环的长度为R,H到E的距离为L ,E到M的距离为X,则M到E的距离为R-X
在快慢指针相遇过程时,快慢指针相遇时所走的路径长度:
fast:L +X + nR slow:L+ X
注意:1.当慢指针进入环时,快指针可能已经在环中绕了n圈了,n至少为1。
因为:快指针先进环走到M的位置,最后又在M的位置与慢指针相遇
2.慢指针进环之后,快指针肯定会在慢指针走一圈之内追上慢指针因为:慢指针进环后,快慢指针之间的距离最多就是环的长度,而两个指针在移动时,每次它们至今的距离都缩减一步,因此在慢指针移动一圈之前快指针肯定是可以追上慢指针的
而快指针速度是满指针的两倍。所以有如下关系是:
2 *(L+X)=L+X+nR
L+X=nR
L=nR-X(n为1,2,3,4..……,n的大小取决于环的大小,环越小n越大)
极端情况下,假设n=1,此时:L=R-X
所以由此得知一个指针从链表起始位置运行,一个指针从相遇点位置绕环,每次都走一步,两个指针无论如何最终都会在入口点的位置相遇。
完整代码如下:
public static ListNode detectCycle(ListNode head) {//给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。if(head==null||head.next==null)return null;ListNode slow=head;ListNode fast=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;if(slow==fast){slow=head;while(slow!=fast){slow=slow.next;fast=fast.next;}return slow;}}return null;}
11.总结
所以对于这10个面试题我们就讲述清楚了,并且我还把其中的部分题目当作特殊方法加入到模拟的无头单向非循环链表类中。
对于该无头单向非循环链表的模拟实现和其具体使用放到码云里了,大家可以看下:无头单向非循环链表的模拟实现和其具体使用(此外还往模拟的链表内部添加了一些特殊方法)
下篇文章将给大家带来LinkedList的模拟实现和具体使用。
在此,我们诚挚地邀请各位大佬们为我们点赞、关注,并在评论区留下您宝贵的意见与建议。让我们共同学习,共同进步,为知识的海洋增添更多宝贵的财富!🎉🎉🎉❤️❤️💕💕🥳👏👏👏
相关文章:

【Java数据结构】详解LinkedList与链表(二)
目录 1.❤️❤️前言~🥳🎉🎉🎉 2.反转一个单链表 3. 找到链表的中间节点 4.输入一个链表,输出该链表中倒数第k个结点。 5.合并两个有序链表 6.链表分割 7. 判定链表的回文结构 8.输入两个链表,找…...

【精读文献】J. Environ. Manage.|青藏高原生态恢复项目下植被覆盖动态及其对生态系统服务的约束效应
目录 文章简介 01 文章摘要 02 研究背景、目标及创新点 2.1 研究背景 2.2 研究现状 03 研究区域与数据集 3.1 研究区域 3.2 研究数据 04 研究方法 4.1 趋势分析 4.2 残差趋势分析 4.3 偏相关 4.4 生态系统服务评价 4.5 约束线的定义和提取 05 研究结果 5.1 植被…...

QT之常用控件
一个图形化界面当然需要有各种各样的控件,QT也不例外,在QT designer中就有提供各种各样的控件,用以开发图形化界面。 而想使用好一个QT控件,就需要了解这些控件。 QWidget 在QT中,所有控件都继承自 QWidget 类&…...

【嵌入式硬件】DRV8874电机驱动
目录 1 芯片介绍 1.1 特性简介 1.2 引脚配置 1.3 最佳运行条件 2 详细说明 2.1 PMODE配置控制模式 2.1.1 PH/EN 控制模式 2.1.2 PWM 控制模式 2.1.3 独立半桥控制模式 2.2 电流感测和调节 2.2.1 IPROPI电流感测 2.2.2 IMODE电流调节 3.应用 3.1设计要求 3.2 设计…...

考研数学:有些无穷小不能用等价无穷小的公式?
今天要给大家分享的笔记是:《有些无穷小虽然是无穷小,但却不能用无穷小的相关公式》:...

谷歌浏览器的平替,内置开挂神器,我已爱不释手!
油猴浏览器正式版是一款基于谷歌Chromium源码开发的浏览器,它集成了集成了强大的油猴扩展(Tampermonkey),使得用户可以轻松安装各种脚本,从而增强网页浏览体验。提供了一个更加个性化和高效的浏览体验。 油猴扩展&…...

UMLChina为什么叒要翻译《分析模式》?
UMLChina受机械工业出版社委托,重新翻译《分析模式》。 Martin Fowler的“Analysis Patterns,Reusable Object Models”,原书出版于1997年,至今为止未出第2版。 2004年,机械工业出版社出版该书中译本《分析模式》。 …...
npm install 安装很慢如何解决?
1. 使用淘宝镜像 淘宝提供了一个更快的 npm 镜像源,可以大大加快依赖包的下载速度。你可以通过以下命令来设置淘宝镜像: npm config set registry https://registry.npmmirror.com然后再次运行 npm install: npm install2. 使用 nrm 切换镜…...

哈夫曼树的构造,哈夫曼树的存在意义--求哈夫曼编码
一:哈夫曼树的构造 ①权值,带权路径长度。 ②一组确定权值的叶子节点可以构造多个不同的二叉树,但是带权路径长度min的是哈夫曼树 ③算法基本思想及其实操图片演示 注:存储结构和伪代码 1 初始化: 构造2n-1棵只有一个根节点的二叉树,parent=rchild=lchild=-1; 其中…...

一个全面了解Xilinx FPGA IP核的窗口:《Xilinx系列FPGA芯片IP核详解》(可下载)
随着摩尔定律的逐渐放缓,传统的芯片设计方法面临着越来越多的挑战。而FPGA以其并行处理能力和可编程性,为解决复杂问题提供了新的途径。它允许设计者在同一个芯片上实现多种不同的功能模块,极大地提高了资源的利用率和系统的综合性能。 FPGA…...

virtualbox识别windows上usb设备
当你插入 USB 时,你的宿主操作系统可以轻松访问它并使用其中的文件。如果需要VirtualBox 的虚拟机也能访问物理机的 USB设备,需要安装安装扩展包管理器。 第一步: 要安装 VirtualBox 扩展包,只需访问 VirtualBox 官方下载页面&a…...

LabVIEW步进电机的串口控制方法与实现
本文介绍了在LabVIEW环境中通过串口控制步进电机的方法,涵盖了基本的串口通信原理、硬件连接步骤、LabVIEW编程实现以及注意事项。通过这些方法,用户可以实现对步进电机的精确控制,适用于各种自动化和运动控制应用场景。 步进电机与串口通信…...

云计算-高级云资源配置(Advanced Cloud Provisioning)
向Bucket添加公共访问(Adding Public Access to Bucket) 在模块5中,我们已经看到如何使用CloudFormation创建和更新一个Bucket。现在我们将进一步更新该Bucket,添加公共访问权限。我们在模块5中使用的模板(third_templ…...

Nginx企业级负载均衡:技术详解系列(17)—— 长连接优化策略与下载服务器高效搭建
你好,我是赵兴晨,97年文科程序员。 今天咱们来聊聊Nginx的两个知识点:Nginx的长连接优化、如何将Nginx配置成下载服务器。 长连接配置详解 在Nginx的配置中,长连接是一个重要的性能优化手段。它允许一个TCP连接上发送多个请求和…...

LabVIEW如何确保步进电机的长期稳定运行
步进电机因其良好的定位精度和控制性,在自动化设备中得到了广泛应用。然而,长期稳定运行对于任何电机系统都是一个重要的挑战。LabVIEW作为一款强大的图形化编程语言,通过其灵活的控制算法和实时监控能力,为步进电机的稳定运行提供…...

vue2 bug 小白求助!!!(未解决,大概是浏览器缓存的问题或者是路由的问题)
我的vue2项目出现了一个超级恶心的bug 具体流程: 页面a点击a标签->到页面b->页面b用户退出刷新页面->点击浏览器的返回按钮返回上一页 返回页面后页面没有刷新导致用户名还显示这 项目中没有用keep-alive缓存 也在设置了key 尝试了window.removeEventLi…...
上海云管平台怎么样?客服电话多少?
云计算已经成为了企业数字化转型的重要一部分,而在上海,云管平台发展更是大势所趋。这不不少小伙伴在问,上海云管平台怎么样?客服电话多少? 上海云管平台怎么样?客服电话多少? 【回答】&#…...

c++程序员为什么要做自己的底层库
五一期间,在家里翻到之前上学时候用的电脑和工作日志,粗略浏览一番,感慨10年岁月蹉跎,仍然没有找到自己技术方向的“道”。遂有感而发,写下此文。 算起来,接触软件开发也有10年时间了,最开始是…...

堆排序-java
这次主要讲了堆排序和堆的基本构造,下一期会详细讲述堆的各种基本操作。 文章目录 前言 一、堆排序 1.题目描述 2.堆 二、算法思路 1.堆的存储 2. 结点下移down 3.结点上移up 4.堆的基本操作 5.堆的初始化 三、代码如下 1.代码如下: 2.读入数据ÿ…...
Android MIPI屏配置
参考资料:RockChip发布的DRM Display Driver Development Guide手册,以及网上大量相关博客资料 首先要拿到《屏幕硬件规格书》和《DataSheet》,软件配置主要依靠DataSheet提供数据支持。 查阅DataSheet里面on sequence和off sequence说明&a…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
3403. 从盒子中找出字典序最大的字符串 I
3403. 从盒子中找出字典序最大的字符串 I 题目链接:3403. 从盒子中找出字典序最大的字符串 I 代码如下: class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...