数据结构(Java实现):链表习题

文章目录

  • 1. 题目列表及链接
  • 2. 题目解析及代码
    • 2.1 删除链表中等于给定值 val 的所有节点
    • 2.2 反转一个单链表
    • 2.3 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
    • 2.4 输入一个链表,输出该链表中倒数第k个结点
    • 2.5 将两个有序链表合并为一个新的有序链表并返回,新链表是通过拼接给定的两个链表的所有节点组成的
    • 2.6 以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前
    • 2.7 链表的回文结构
    • 2.8 输入两个链表,找出它们的第一个公共结点
    • 2.9 给定一个链表,判断链表中是否有环
    • 2.10 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL

1. 题目列表及链接

  1. 删除链表中等于给定值 val 的所有节点。
  2. 反转一个单链表。
  3. 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
  4. 输入一个链表,输出该链表中倒数第k个结点。
  5. .将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
  6. 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
  7. 链表的回文结构。
  8. 输入两个链表,找出它们的第一个公共结点。
  9. 给定一个链表,判断链表中是否有环。
  10. 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL 。

2. 题目解析及代码

2.1 删除链表中等于给定值 val 的所有节点

题目解析
这道题需要移除所有的目标节点,我们可以使用两个辅助节点 prev(前驱节点),cur(遍历节点)。prev在cur前面。开始使用cur往前遍历,当cur指向的节点不是目标节点,prev跟随cur一起往后移动一步,当cur指向的节点是目标节点,使cur继续往后遍历,prev不再往后走,并使prev的next为cur遍历后的位置。
在这里插入图片描述
代码示例

class Solution {public ListNode removeElements(ListNode head, int val) {//先判断传入指针是否为空if(head==null){return head;}//上面如果不判断,下面这行可能会有空指针异常ListNode cur=head.next;ListNode prev=head;//进入循环开始遍历while (cur!=null){//如果不是目标节点,prev和cur一起往后移动if (cur.val != val) {prev = cur;cur=cur.next;//这一步可以合起来,这里方便理解}else{//否则只移动cur,并把prev的next指向curprev.next=cur.next;cur=cur.next;}}//最后判断头节点是否为目标节点//这一步也可以在最前面来写,但是要以循环的方式,防止头节点一直为目标节点if(head.val==val){head=head.next;}return head;}
}

2.2 反转一个单链表

题目解析
要反转一个链表,我们采用头插法,然后一步一步往后遍历节点,将遍历到的节点(cur)的next指向头结点,并且让当前节点设置成头结点。此事我们就需要考虑,cur的next指向改变了,怎么才能让cur正常遍历完原来的链表,这时我们使用curN来指向原链表cur的next。
在这里插入图片描述

代码示例

class Solution {public ListNode reverseList(ListNode head) {if(head==null){//判断传入头节点是否为空return null;}//如果不加上面判断,下面这行可能引发空指针异常ListNode cur=head.next;  //使尾节点的next置nullhead.next=null;//遍历初始链表,并反转链表while(cur!=null){ListNode curN=cur.next;//防止初始链表的顺序丢失//头插cur.next=head;head=cur;//使cur的顺序回到初始链表的顺序cur=curN;}return head;}
}

2.3 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点

题目解析
解法1:首先想到的是把链表的节点个数求出来,然后遍历节点个数/2次就能得到中间节点。
解法2:使用快慢指针,快指针一次走两个节点,慢指针一次走一个节点。根据经典数学问题:追击问题可以知道,快指针走的路程是慢指针的两倍,所以当快指针遍历完链表后,慢指针就刚好到链表的中间节点。

代码示例

//解法1
class Solution {public ListNode middleNode(ListNode head) {int count = size(head);ListNode cur = head;for(int i=0;i<count/2;i++,cur=cur.next){}//遍历节点个数/2次就能得到中间节点return cur;}public int size(ListNode head){//计算链表长度int count=0;ListNode cur=head;while(cur!=null){cur=cur.next;count++;}return count;}
}
//解法2
class Solution {public ListNode middleNode(ListNode head) {ListNode fast = head;//快指针ListNode slow = head;//慢指针//这里判断条件顺序不能改变//否则当fast为null时,fast.next可能会有空指针异常while(fast!=null && fast.next!=null){fast=fast.next.next;slow=slow.next;}return slow;}
}

2.4 输入一个链表,输出该链表中倒数第k个结点

题目解析
给的题目保证了k的位置是合法的,但是为了严谨我们首先要判断传入的节点是否合法。(有关链表的题目都要注意传入的形参的合法性)。这题我们同样可以使用快慢指针的思想,先让快指针移动k-1个节点。然后快慢指针一起往后移动,当快指针遍历完链表,慢指针就指向链表的倒数第k个节点。
代码示例

class Solution {public int kthToLast(ListNode head, int k) {if(k<=0||head==null){//判断传入参数是否合法return -1;}ListNode fast=head;//快指针ListNode slow=head;//慢指针//快指针先走k-1for(int i=0;i<k-1;i++){fast=fast.next;if(fast==null){//链表到头了还没走完k-1个节点,k的位置就不合法return -1;}}//快慢指针一起往后移动while(fast.next!=null){//快指针遍历完结束fast=fast.next;slow=slow.next;}return slow.val;//返回慢指针的值}
}

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

题目解析
这里我们创建一个虚拟头结点,然后分别遍历两个链表,当我们去遍历每个节点的时候开始比较两个节点的值。小的那个值尾插到新头的链表。最后,如果某条链表遍历完成,另一条链表的剩余部分直接尾插。
在这里插入图片描述
代码示例

class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {if(list1==null){//如果list1为null,返回list2return list2;}else if(list2==null){//如果list2为null,返回list1return list1;}ListNode list = new ListNode();//虚拟头结点ListNode cur = list;//辅助尾插while(true){if(list1.val<list2.val){//比较值cur.next=list1;//尾插list1=list1.next;//list1往后遍历}else{cur.next=list2;//尾插list2=list2.next;//list2遍历}cur=cur.next;//cur往后走以便下一次尾插//下面当某一条链表为null时,另一条链表的剩余部分直接尾插if(list1==null){cur.next=list2;break;}else if(list2==null){cur.next=list1;break;}}//最后虚拟头结点的next即为合并的链表return list.next;}
}

2.6 以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

题目解析
我们可以将一个链表分为两条链表,一条小于x的节点,一条大于或等于x的节点。然后分别记录两条链表的头结点和尾节点。然后将第一条链表的尾结点接入第二条链表的头结点。此时有一个特殊情况:传入链表的节点都小于x或者传入链表的节点都大于等于x。而且要注意,第二条链表的尾的next可能不指向空。
代码示例

public class Partition {public ListNode partition(ListNode pHead, int x) {if(pHead==null){//判断传入链表是否为nullreturn null;}ListNode bs=null;//第一条链表的头ListNode be=null;//第一条链表的尾(遍历)ListNode as=null;//第二条链表的头ListNode ae=null;//第二条链表的尾(遍历)ListNode cur=pHead;//遍历当前链表while(cur!=null){if(cur.val<x){//小于x的节点插到第一条链表if(bs==null){//如果头为null,将节点设置为头节点bs=be=cur;}else{//头节点部位null,尾插节点be.next=cur;be=be.next;}}else{//大于等于x的节点插到第二条链表if(as==null){//如果头为null,将节点设置为头节点as=ae=cur;}else{//头节点部位null,尾插节点ae.next=cur;ae=ae.next;}}cur=cur.next;}//特殊情况//传入链表的节点都小于x或者传入链表的节点都大于等于xif(bs==null){return as;}be.next=as;//第二条链表的尾的next可能不指向空if(as!=null){ae.next=null;}return bs;}
}

2.7 链表的回文结构

题目解析
首先利用快慢指针找到链表的中间节点,然后从中间节点往右开始进行链表的翻转。最后从两头开始往中间遍历,一个一个节点比较,直到遍历到链表的中点。
在这里插入图片描述

代码示例

public class PalindromeList {public boolean chkPalindrome(ListNode A) {//判断传入的链表是否为nullif(A==null){return true;}//快慢指针找到中间节点ListNode slow=A;ListNode fast=A;while(fast!=null&&fast.next!=null){slow=slow.next;fast=fast.next.next;}//开始翻转中间节点往右的链表ListNode cur=slow.next;while(cur!=null){ListNode curN=cur.next;cur.next=slow;slow=cur;cur=curN;}//从两头开始往中间遍历while(A!=slow){//当A==slow时,链表为奇数个节点if(slow.val!=A.val){//当遍历过程中有值不相等就不是回文链表return false;}if(A.next==slow){//当A.next==slow,链表为偶数个节点return true;}//遍历slow=slow.next;A=A.next;}//成功完成遍历,链表为回文链表return true;}
}

2.8 输入两个链表,找出它们的第一个公共结点

题目解析
在这里插入图片描述
tip:链表相交不可能只相交一个节点,因为节点的next只有一个。
首先我们求出两条链表的长度。然后用唱的那根链表先走差值个节点,然后两条链表一起往后走,直到相遇就说明两条链表相交且相遇节点就是首个公共节点。反之,当链表遍历完了还没有相遇,就不存在公共节点。
在这里插入图片描述
代码示例

public class Solution {public ListNode getIntersectionNode(ListNode head1, ListNode head2) {//如果其中一条链表为null,直接返回nullif(head1==null||head2==null){return null;}//遍历两条链表求长度ListNode cur1=head1;ListNode cur2=head2;int count1=0;int count2=0;while(cur1!=null){count1++;cur1=cur1.next;}while(cur2!=null){count2++;cur2=cur2.next;}//使指针重新指向链表头cur1=head1;cur2=head2;//让长链表先走差值步if(count1>count2){for(int i=0;i<count1-count2;i++){cur1=cur1.next;}}else{for(int i=0;i<count2-count1;i++){cur2=cur2.next;}}//两条链表同时往前走while(cur1!=null){if(cur1==cur2){//当两指针相遇就到第一个公共节点了return cur1;}cur1=cur1.next;cur2=cur2.next;}//遍历完还没有相遇就不存在公共节点return null;}
}

2.9 给定一个链表,判断链表中是否有环

题目解析
这里我们还是使用快慢指针来解题,当链表存在环时,快慢指针一定会在环种相遇。没环,快指针先走到结尾。
思考
为什么快指针每次走两步,慢指针走一步可以?
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
快指针一次走3步,走4步,…n步行吗?
在这里插入图片描述

代码示例

public class Solution {public boolean hasCycle(ListNode head) {//这理解不需要判断传入链表是否为null了,因为下面不会引发空指针异常ListNode fast=head;//快指针ListNode slow=head;//慢指针//循环条件顺序不能变,可能会造成空指针异常while(fast!=null&&fast.next!=null){fast=fast.next.next;slow=slow.next;if(fast==slow){//当相遇存在环return true;}}//结束循环没有相遇,不存在环return false;}
}

2.10 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL

题目解析
首先我们使用快慢指针找到相遇节点。
在这里插入图片描述
在这里插入图片描述
当得到相遇节点后,使fast从新回到头,然后一起出发,再次相遇就是环的入口。
代码示例

public class Solution {public ListNode detectCycle(ListNode head) {//快慢指针开始运动ListNode fast=head;ListNode slow=head;while(fast!=null&&fast.next!=null){fast=fast.next.next;slow = slow.next;if(fast==slow){//相遇结束循环break;}}//当不是if条件使循环结束,这个链表无环if(fast==null||fast.next==null){return null;}//fast回到头fast=head;//一起运动直至相遇while(fast!=slow){fast=fast.next;slow=slow.next;}return fast;}
}

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

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

相关文章

iTransformer时序模型改进——基于SENet和TCN的倒置Transformer,性能暴涨

1数据集介绍 ETT(电变压器温度)&#xff1a;由两个小时级数据集&#xff08;ETTh&#xff09;和两个 15 分钟级数据集&#xff08;ETTm&#xff09;组成。它们中的每一个都包含 2016 年 7 月至 2018 年 7 月的七种石油和电力变压器的负载特征。 数据集链接&#xff1a; https…

深度学习入门-第4章-神经网络的学习

学习就是从训练数据中自动获取最优权重参数的过程。引入损失函数这一指标&#xff0c;学习的目的是找出使损失函数达到最小的权重参数。使用函数斜率的梯度法来找这个最小值。 人工智能有两派&#xff0c;一派认为实现人工智能必须用逻辑和符号系统&#xff0c;自顶向下看问题…

Sass实现网页背景主题切换

Sass 实现网页背景主题切换 前言准备工作一、 简单的两种主题黑白切换1.定义主题2. 添加主题切换功能3. 修改 data-theme 属性 二、多种主题切换1. 定义主题2. 动态生成 CSS 变量1.遍历列表2.遍历映射3.高级用法 3. 设置默认主题4. 切换功能HTML 三、多种主题多种样式切换1. 定…

Java数组的定义与使用

目录 1. 数组的基本概念 1.1为什么要使用数组 1.2 什么是数组 1.3 数组的创建及初始化 1.3.1 数组的创建 1.3.2 数组的初始化 1. 动态初始化 2. 静态初始化 1.4 数组的使用 1.4.1 数组中元素访问 1.4.2 遍历数组 2. 数组是引用类型 2.1 基本类型变量与引用类型变量…

【C++从小白到大牛】C++智能指针的使用、原理和分类

目录 1、我们为什么需要智能指针&#xff1f; 2、内存泄露 2.1 什么是内存泄漏&#xff0c;内存泄漏的危害 2.2如何避免内存泄漏 总结一下: 3.智能指针的使用及原理 3.1 RAII 3.2关于深拷贝和浅拷贝更深层次的理解&#xff1a; 3.3 std::auto_ptr 3.4 std::unique_pt…

Springboot里集成Mybatis-plus、ClickHouse

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; Springboot里集成Mybati…

Overleaf参考文献由 BibTex 转 \bibitem 格式

目录 Overleaf参考文献由 BibTex 转 \bibitem 格式一、获取引用论文的BibTex二、编写引用论文对应的bib文件三、编写生成bibitem的tex文件四、转化bibitem格式 参考资料 Overleaf参考文献由 BibTex 转 \bibitem 格式 一、获取引用论文的BibTex 搜索论文引用点击BibTex 跳转出…

怎样快速搭建 Linux 虚拟机呢?(vagrant 篇)

作为一名Coder&#xff08;程序员或码农&#xff09;&#xff0c;供职于中小型互联网公司&#xff0c;而你恰恰偏向于服务端&#xff0c;那么&#xff0c;产品部署在生产环境的艰巨任务&#xff0c;便毫无疑问的落在你身上了。 只有大厂&#xff08;大型互联网&#xff09;企业…

Ps:首选项 - 界面

Ps菜单&#xff1a;编辑/首选项 Edit/Preferences 快捷键&#xff1a;Ctrl K Photoshop 首选项中的“界面” Interface选项卡可以定制 Photoshop 的界面外观和行为&#xff0c;从而创建一个最适合自己工作习惯和需求的工作环境。这些设置有助于提高工作效率&#xff0c;减轻眼…

Simple RPC - 07 从零开始设计一个服务端(下)_RPC服务的实现

文章目录 PreRPC服务实现服务注册请求处理 设计&#xff1a; 请求分发机制 Pre Simple RPC - 01 框架原理及总体架构初探 Simple RPC - 02 通用高性能序列化和反序列化设计与实现 Simple RPC - 03 借助Netty实现异步网络通信 Simple RPC - 04 从零开始设计一个客户端&#…

# 利刃出鞘_Tomcat 核心原理解析(九)-- Tomcat 安全

利刃出鞘_Tomcat 核心原理解析&#xff08;九&#xff09;-- Tomcat 安全 一、Tomcat专题 - Tomcat安全 - 配置安全 1、 删除 tomcat 的 webapps 目录下的所有文件&#xff0c;禁用 tomcat 管理界面. 如下目录均可删除&#xff1a; D:\java-test\apache-tomcat-8.5.42-wind…

数据结构-KMP算法

先解决 前缀与后缀串的最长匹配长度信息(前缀或后缀都不能取整体)。如下 位置6的前缀最长串就是abcab(不能取全部,即不能为abcabc) 位置6的后缀最长串就是bcabc(不能取全部,即不能为abcabc)

[Linux#47][网络] 网络协议 | TCP/IP模型 | 以太网通信

目录 1.网络协议 2.协议分层 2.1 OSI七层模型 2.2TCP/IP五层(四层)模型 2.3 以太网通信 1.网络协议 "协议"本质就是一种约定 计算机之间的传输媒介是光信号和电信号. 通过 "频率" 和 "强弱" 来表示 0 和 1 这样的 信息. 要想传递各种不同…

HTML+CSS浮动和清除浮动的效果及其应用场景举例

一、清除浮动的效果 解释 .container&#xff1a;用于展示浮动和清除浮动效果的容器&#xff0c;具有边框和背景色以便于区分。 .float-box&#xff1a;浮动元素&#xff0c;用不同的背景色标识。 .clearfix&#xff1a;使用伪元素清除浮动的类&#xff0c;应用于第二个容器。 …

IDEA 2024.2.0.2 使用 Jrebel and XRebel 热部署

安装 激活 工具网站中url和邮箱复制进去 设置 允许项目自动构建 允许开发过程中自动部署

python面向对象—封装、继承、多态

封装 ① 把现实世界中的主体中的属性和方法书写到类的里面的操作即为封装 ② 封装可以为属性和方法添加为私有权限&#xff0c;不能直接被外部访问 在面向对象代码中&#xff0c;我们可以把属性和方法分为两大类&#xff1a;公有&#xff08;属性、方法&#xff09;、私有&…

SQLSugar进阶使用:高级查询与性能优化

文章目录 前言一、高级查询1.查所有2.查询总数3.按条件查询4.动态OR查询5.查前几条6.设置新表名7.分页查询8.排序 OrderBy9.联表查询10.动态表达式11.原生 Sql 操作 &#xff0c;Sql和存储过程 二、性能优化1.二级缓存2.批量操作3.异步操作4.分表组件&#xff0c;自动分表5.查询…

LCP:60 排列序列[leetcode-4]

LCP:60 排列序列 给出集合 [1,2,3,...,n]&#xff0c;其所有元素共有 n! 种排列。 按大小顺序列出所有排列情况&#xff0c;并一一标记&#xff0c;当 n 3 时, 所有排列如下&#xff1a; "123""132""213""231""312"&quo…

09 复合查询

前面的查询都是对一张表进行查询&#xff0c;但这远远不够 基本查询回顾 查询工资高于500或岗位为MANAGER的雇员&#xff0c;同时还要满足他们的姓名首字母为大写的J select * from EMP where (sal>500 or job‘MANAGER’) and ename like ‘J%’; 按照部门号升序而雇员的…

【git】git进阶-blame/stash单个文件/rebase和merge/cherry-pick命令/reflog和log

文章目录 git blame查看单个文件修改历史git stash单个文件git rebase命令git rebase和git merge区别git cherry-pick命令git reflog和git log区别 git blame查看单个文件修改历史 git blame&#xff1a;查看文件中每行最后的修改作者 git blame your_filegit log和git show结合…