【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的模拟实现和具体使用。

在此,我们诚挚地邀请各位大佬们为我们点赞、关注,并在评论区留下您宝贵的意见与建议。让我们共同学习,共同进步,为知识的海洋增添更多宝贵的财富!🎉🎉🎉❤️❤️💕💕🥳👏👏👏 

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

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

相关文章

栈与队列练习题(2024/5/31)

1有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的…

云服务和云备份的区别是什么?

随着云计算的兴起&#xff0c;云备份与云服务被越来越多的企业和个人所关注&#xff0c;在云计算中云服务与云备份之间还是有一定的区别的&#xff0c;本文就来介绍一下云服务和云备份之间的区别。 云服务和云备份主要的区别在备份对象、推荐场景和数据一致性等方面。 备份对象…

打印机的ip不同且连不上

打印机的ip不同且连不上 1.问题分析2.修改网段3.验证网络 1.问题分析 主要是打印机的网段和电脑不在同一个网段 2.修改网段 3.验证网络

Web前端三大主流框:React、Vue 和 Angular

在当今快速发展的 Web 开发领域&#xff0c;选择合适的前端框架对于项目的成功至关重要。React、Vue 和 Angular 作为三大主流前端框架&#xff0c;凭借其强大的功能和灵活的特性&#xff0c;赢得了众多开发者的青睐。本文将对这三大框架进行解析&#xff0c;帮助开发者了解它们…

dubbo复习:(12)服务器端的异步和客户端的异步调用

一、服务器端接口的定义和实现&#xff1a; package cn.edu.tju.service;import java.util.concurrent.CompletableFuture;public interface AsyncService {/*** 同步调用方法*/String invoke(String param);/*** 异步调用方法*/CompletableFuture<String> asyncInvoke(…

C/C++学习笔记 C读取文本文件

1、简述 要读取文本文件&#xff0c;需要按照以下步骤操作&#xff1a; 首先&#xff0c;使用该函数打开文本文件fopen()。其次&#xff0c;使用fgets()或fgetc()函数从文件中读取文本。第三&#xff0c;使用函数关闭文件fclose()。 2、每次从文件中读取一个字符 要从文本文…

整理一下win7系统java、python等各个可安装版本

最近使用win7系统&#xff0c;遇到了很多版本不兼容的问题&#xff0c;把我现在安装好的可使用的分享给大家 jdk 1.8 maven-3.9.6 centos 7 python 3.7.4 docker DockerToolbox-18.01.0-ce win10是直接一个docker软件&#xff0c;win7要安装这三个 datagrip-2020.2.3 d…

2.1Docker安装MySQL8.0

2.1 Docker安装MySQL8.0 1.拉取MySQL docker pull mysql:latest如&#xff1a;拉取MySQL8.0.33版本 docker pull mysql:8.0.332. 启动镜像 docker run -p 3307:3306 --name mysql8 -e MYSQL_ROOT_PASSWORDHgh75667% -d mysql:8.0.33-p 3307:3306 把mysql默认的3306端口映射…

CentOs-7.5 root密码忘记了,如何重置密码?

VWmare软件版本&#xff1a;VMware Workstation 16 Pro Centos系统版本&#xff1a;CentOS-7.5-x86 64-Minimal-1804 文章目录 问题描述如何解决&#xff1f; 问题描述 长时间没有使用Linux系统&#xff0c;root用户密码忘记了&#xff0c;登陆不上系统&#xff0c;如下图所示…

【网络安全】Web安全基础 - 第一节:使用软件及环境介绍

VMware VMware&#xff0c;是全球云基础架构和移动商务解决方案的佼佼者。 VMware可是一个总部位于美国加州帕洛阿尔托的计算机虚拟化软件研发与销售企业呢。简单来说&#xff0c;它就是通过提供虚拟化解决方案&#xff0c;让企业在数据中心改造和公有云整合业务上更加得心应…

QImage和QPixmap的区别和使用

一、基本概念和特点 QImage 概念&#xff1a;QImage是Qt库中用于处理图像数据的一个类。它提供了直接访问和操作图像像素的接口。特点&#xff1a; 可以独立于屏幕分辨率和设备处理图像。支持读取和保存多种图像格式&#xff0c;如PNG、JPEG、BMP等。可以在没有图形界面的情况…

图论第二天

最近加班时间又多了&#xff0c;随缘吧&#xff0c;干不动就辞呗。真是想歇几天了&#xff0c;题不能停&#xff01;&#xff01;今天目前只做了一道题&#xff0c;先用两种方式把他搞出来。 695. 岛屿的最大面积 class Solution { public:int neighbor[4][2] {1,0,0,-1,-1,…

Linux系统管理基础002

Linux系统管理基础之文件管理二 Linux文件管理是系统管理中的重要组成部分 1.文件与目录的基本概念 2. 特殊目录与文件 3. 文件与目录的操作 4. 文件权限管理 5. 查找处理文件 6. 关联技巧 今天给大家介绍一下目录的结构 1.文件与目录的基本概念 管理类目录&#xff1a; …

FreeRTOS基础(三):动态创建任务

上一篇博客&#xff0c;我们讲解了FreeRTOS中&#xff0c;我们讲解了创建任务和删除任务的API函数&#xff0c;那么这一讲&#xff0c;我们从实战出发&#xff0c;规范我们在FreeRTOS下的编码风格&#xff0c;掌握动态创建任务的编码风格&#xff0c;达到实战应用&#xff01; …

用贪心算法进行10进制整数转化为2进制数

十进制整数转二进制数用什么方法&#xff1f;网上一搜&#xff0c;大部分答案都是用短除法&#xff0c;也就是除2反向取余法。这种方法是最基本最常用的&#xff0c;但是计算步骤多&#xff0c;还容易出错&#xff0c;那么还有没有其他更好的方法吗&#xff1f; 一、短除反向取…

AdroitFisherman模块安装日志(2024/5/31)

安装指令 pip install AdroitFisherman-0.0.29.tar.gz -v 安装条件 1:Microsoft Visual Studio Build Tools 2:python 3.10.x 显示输出 Using pip 24.0 from C:\Users\12952\AppData\Local\Programs\Python\Python310\lib\site-packages\pip (python 3.10) Processing c:\u…

matlab GUI界面设计

【实验内容】 用MATLAB的GUI程序设计一个具备图像边缘检测功能的用户界面&#xff0c;该设计程序有以下基本功能&#xff1a; &#xff08;1&#xff09;图像的读取和保存。 &#xff08;2&#xff09;设计图形用户界面&#xff0c;让用户对图像进行彩色图像到灰度图像的转换…

3-哈希表-21-两个数组的交集-LeetCode349

3-哈希表-21-两个数组的交集-LeetCode349 参考&#xff1a;代码随想录 LeetCode: 题目序号349 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&…

2.1 OpenCV随手简记(二)

为后续项目学习做准备&#xff0c;我们需要了解LinuxOpenCV、Mediapipe、ROS、QT等知识。 一、图像显示与保存 1、基本原理 1.1 图像像素存储形式 首先得了解下图像在计算机中存储形式&#xff1a;(为了方便画图&#xff0c;每列像素值都写一样了)。对于只有黑白颜色的灰度…

[有监督学习]2.详细图解正则化

正则化 正则化是防止过拟合的一种方法&#xff0c;与线性回归等算法配合使用。通过向损失函数增加惩罚项的方式对模型施加制约&#xff0c;有望提高模型的泛化能力。 概述 正则化是防止过拟合的方法&#xff0c;用于机器学习模型的训练阶段。过拟合是模型在验证数据上产生的误…