数据结构(Java版)第七期:LinkedList与链表(二)

专栏:数据结构(Java版)
个人主页:手握风云
一、链表的实现(补)
接上一期,下面我们要实现删除所有值为key的元素,这时候有的老铁就会想用我们上一期中讲到的remove方法,循环使用remove方法,去删除完值为key的元素。如下图所示,比如我们要删除值为22的节点,使用remove方法循环,此时这个算法的时间复杂度就会为,算法效率就会比较低。那我们能不能只让cur遍历一遍这个链表,就删除所有值为22的节点呢?

@Overridepublic void removeAllKey(int key) {ListNode cur = head.next;ListNode prev = head;if(head == null){return;}while(cur != null){if(cur.val == key){prev.next = cur.next;}else{prev = cur;}cur = cur.next;}}
这样我们就可以实现删除所有职位key的元素,但我们要思考一下,这段代码的问题。我们来运行测试一下。
public class Main {public static void main(String[] args) {IList mySingleList = new MySingleList();mySingleList.addLast(22);mySingleList.addLast(22);mySingleList.addLast(22);mySingleList.addLast(33);mySingleList.display();mySingleList.removeAllKey(22);mySingleList.display();}
}

我们就会发现运行结果里面还有22。如下图所示,我们会看到,当cur走到第三个节点时,第二个22就会变成新的头,走得时候又会把新的22给忽略掉。我们可以这样解决这个问题。

@Overridepublic void removeAllKey(int key) {ListNode cur = head.next;ListNode prev = head;if(head == null){return;}while(head.val == key){head = head.next;}while(cur != null){if(cur.val == key){prev.next = cur.next;}else{prev = cur;}cur = cur.next;}}
二、链表中经典的面试题
2.1. 反转链表
反转链表是将链表的结构进行反转,同时包括数据与地址。过程如下图所示。

对于这道题,我们可以采用头插的思想来解决。我们需要定义两个变量cur和curNext,利用以下代码来解决。我们先把head.next置为空,把cur方法到第二个节点上,然后把第二个节点采用头插的方法进行插入。可我们把cur改了之后,就会找不到下一个节点了,我们再定义一个curNext
while(cur != null){curNext = cur.next;cur.next = head;head = cur;cur = curNext;
}
2.2. 链表的中间结点
第一种方法,可以先求出链表长度,再定义一个引用,走到len/2的位置。但这种方法需要先定义cur节点去遍历一边数组得出链表的长度,再定义一个len变量走到中间节点的位置,这样就会需要遍历两遍链表。那我们能不能只遍历一遍数组得出中间节点。
类比一下,试想两个人赛跑,其中一人是另一个人速度的两倍,当速度快的到达终点时,速度慢的刚到达中点。同样,我们定义一个fast和slow两个引用变量。fast一次走两步,slow一次走一步。如果链表有奇数个结点时,当fast.next==null时,slow指向中间结点;如果链表有偶数个结点时,当fast==null时,slow指向中间结点。
public class Solution {static class ListNode{private int val;private Solution.ListNode next;public ListNode(Solution.ListNode next) {this.next = next;}public ListNode(int val, Solution.ListNode next) {this.val = val;this.next = next;}}public ListNode middleNode(ListNode head){if(head == null){return null;}ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null){
//这里不能是||,因为||无法到达链表的尾部
//两个条件的顺序不能互换,因为fast为空,fast.next就会空指针异常fast = fast.next.next;slow = slow.next;}return slow;}public static void main(String[] args) {ListNode node5 = new ListNode(5,null);ListNode node4 = new ListNode(4,node5);ListNode node3 = new ListNode(3,node4);ListNode node2 = new ListNode(2,node3);ListNode node1 = new ListNode(1,node2);Solution solution = new Solution();ListNode middleNode = solution.middleNode(node1);System.out.println(middleNode.val);}
}
2.3. 返回倒数第k个结点
我们依然可以参照上面的双引用的例子,先让slow不动,fast引用先走k-1步。然后两个引用在同时走。当fast走到最后的时候,slow就能走到倒数第k个结点。
public class Solution {static class ListNode{int val;ListNode next;public ListNode(){}public ListNode(int val) {this.val = val;}public ListNode(int val, ListNode next) {this.val = val;this.next = next;}}public int kthToLast(ListNode head, int k){ListNode fast = head;ListNode slow = head;int count = 0;while(count != k-1){fast = fast.next;count++;}while(fast.next != null){fast = fast.next;slow = slow.next;}return slow.val;}
}
这样的代码还不是特别严谨的。加入我们输入了5个结点,要求我们返回第6个结点,那我们的fast就需要走5步,直接指向了空指针,我们可以再写一个if语句来返回-1。或者是我们可以写成异常来接收,但在OJ测试上,异常不会通过。
if(fast == null){return -1;
}
以下为完整代码:
import java.util.Scanner;public class Solution {static class ListNode{int val;ListNode next;public ListNode(){}public ListNode(int val) {this.val = val;}public ListNode(int val, ListNode next) {this.val = val;this.next = next;}}public int kthToLast(ListNode head, int k){ListNode fast = head;ListNode slow = head;int count = 0;while(count != k-1){fast = fast.next;if(fast == null){return -1;}count++;}while(fast.next != null){fast = fast.next;slow = slow.next;}return slow.val;}public static void main(String[] args) {Scanner in = new Scanner(System.in);ListNode node5 = new ListNode(5,null);ListNode node4 = new ListNode(4,node5);ListNode node3 = new ListNode(3,node4);ListNode node2 = new ListNode(2,node3);ListNode node1 = new ListNode(1,node2);int k = in.nextInt();Solution solution = new Solution();int result = solution.kthToLast(node1,k);System.out.println(result);}
}
2.4. 合并两个有序链表

两个链表合并之后,要满足升序的条件,就需要对两个链表所指向的结点值进行比较,这就需要两个引用都不能为空。我们先定义一个傀儡结点newH,如上图所示,起初headA的val值比headB的val值小,那么headA就会指向下一个结点,再把0x23赋给我们的傀儡结点,再与headB的val值进行比较。那我们就可以写一个循环来对val进行比较。
我们还需要再定义一个ListNode.tmp,当headA走到下一个结点时,tmp走到上一个结点,这样就能保证刚进行比较的两个结点中最小的结点值是新创建链表的最后一个结点。
while(headA != null && headB != null){if(headA.val < headB.val){tmp.next = headA;headA = headA.next;tmp = tmp.next;} else {tmp.next = headB;headB = headB.next;tmp = tmp.next;}
}
在这个循环当中,一定会出现一种情况,其中一个链表先走完,而另一个链表还没有走完,此时先走完的链表已经指向空引用了,while循环就会跳出。我们利用下面的伪代码来遍历未完成的结点。
if(headA != null){tmp.next = headA;
} else {tmp.next = headB;
}
以下为完整代码:
public class Solution {static class ListNode{int val;ListNode next;public ListNode(){}public ListNode(int val) {this.val = val;}public ListNode(int val, ListNode next) {this.val = val;this.next = next;}}public ListNode mergeTwoLists(ListNode list1, ListNode list2){ListNode newH = new ListNode(-1);ListNode tmp = newH;while(list1 != null && list2 != null){if(list1.val < list2.val){tmp.next = list1;list1 = list1.next;} else {tmp.next = list2;list2 = list2.next;}tmp = tmp.next;}if(list1 != null){tmp.next = list1;} else {tmp.next = list2;}return newH.next;}public static void main(String[] args) {ListNode list1 = new ListNode(1);list1.next = new ListNode(2);list1.next.next = new ListNode(4);ListNode list2 = new ListNode(0);list2.next = new ListNode(3);list2.next.next = new ListNode(4);Solution solution = new Solution();ListNode mergedList = solution.mergeTwoLists(list1,list2);while (mergedList != null) {System.out.print(mergedList.val + " ");mergedList = mergedList.next;}}
}
相关文章:
数据结构(Java版)第七期:LinkedList与链表(二)
专栏:数据结构(Java版) 个人主页:手握风云 一、链表的实现(补) 接上一期,下面我们要实现删除所有值为key的元素,这时候有的老铁就会想用我们上一期中讲到的remove方法,循环使用remove方法&#…...
ant-design-vue 1.X 通过id获取a-input组件失败
1.ant-design-vue 1.X 问题描述 当我在a-form组件中,以v-decorator指令绑定表单组件时,无法根据我设置的verify-code-input获取元素 <a-input type"text" id"verify-code-input" class"paIpt":placeholder"$t(…...
Flutter:吸顶效果
在分页中,实现tab吸顶。 TDNavBar的screenAdaptation: true, 开启屏幕适配。 该属性已自动对不同手机状态栏高度进行适配。我们只需关注如何实现吸顶。 view import package:ducafe_ui_core/ducafe_ui_core.dart; import package:flutter/material.dart; import p…...
MATLAB语言的数据类型
MATLAB语言的数据类型详解 MATLAB(矩阵实验室)是一种广泛应用于科学计算、数据分析、算法开发及模型构建的高性能语言和环境。MATLAB的强大之处不仅在于其丰富的数学工具和可视化功能,还有其灵活多变的数据类型。这篇文章将详细介绍MATLAB中…...
priority_queue优先队列
目录 1. 最短路径算法(Dijkstra算法) 应用场景: 优先队列的作用: 2. 最小生成树算法(Prim算法) 应用场景: 优先队列的作用: 3. 哈夫曼编码(Huffman Coding&#x…...
HarmonyOS 鸿蒙Next 预览pdf文件
HarmonyOS 鸿蒙Next 预览pdf文件 1、使用filePreview 2、使用web组件 在线pdf(网址是直接下载的,不是直接可以预览的),先下载再预览 import media from ohos.multimedia.media;import web_webview from ohos.web.webview;import …...
vscode开启调试模式,结合Delve调试器调试golang项目详细步骤
1.前期准备 (1).在vs code中的扩展程序中搜索并安装Go扩展程序 (2).安装 Delve 调试器 go install github.com/go-delve/delve/cmd/dlvlatest (3).打开vs code的命令面板,输入Go: Install/Update Tools,并单击该命令执行,安装或更新Go语…...
身份鉴权(PHP)(小迪网络安全笔记~
免责声明:本文章仅用于交流学习,因文章内容而产生的任何违法&未授权行为,与文章作者无关!!! 附:完整笔记目录~ ps:本人小白,笔记均在个人理解基础上整理,…...
【git】-初始git
一、什么是版本控制? 二、Git的安装 三、掌握Linux常用命令 四、Git基本操作 1、提交代码 2、查看历史提交 3、版本回退 一、什么是版本控制? 版本控制是一种用于记录文件或项目内容变化的系统。它通过版本标识和版本历史记录来管理不同版本&#…...
CSS 盒模型
盒模型 CSS盒模型是网页布局的核心概念之一,它描述了网页元素的物理结构和元素内容与周围元素之间的关系。根据W3C规范,每个HTML元素都被视为一个矩形盒子,这个盒子由以下四个部分组成: 内容区(Content areaÿ…...
[0405].第05节:搭建Redis主从架构
Redis学习大纲 一、3主3从的集群配置: 1.1.集群规划 1.分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下: 2.每组是一主一从&#x…...
6 分布式限流框架
限流的作用 在API对外互联网开放的情况下,是无法控制调用方的行为的。当遇到请求激增或者黑客攻击的情况下,会导致接口占用大量的服务器资源,使得接口响应效率的降低或者超时,更或者导致服务器宕机。 限流是指对应用服务进行限制…...
sosadmin相关命令
sosadmin命令 以下是本人翻译的官方文档,如有不对,还请指出,引用请标明出处。 原本有个对应表可以跳转的,但是CSDN的这个[](#)跳转好像不太一样,必须得用html标签,就懒得改了。 sosadmin help 用法 sosadm…...
关于大数据的基础知识(四)——大数据的意义与趋势
成长路上不孤单😊😊😊😊😊😊 【14后😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于大数据的基础知识(四&a…...
【EI,Scopus检索 | 往届均已检索见刊】第四届智能系统、通信与计算机网络国际学术会议(ISCCN 2025)
重要信息: 大会官网:更多详情【论文投稿】 截稿时间:以官网信息为准 大会时间:2025年2月21-23日 接受/拒稿通知:投稿后3-5个工作日内 收录检索:EI,Scopus 出版信息: 本会议所有…...
smplx blender插件笔记
目录 liunx安装: liunx安装: pip install smplx 这个创建模型报错 SMPL_blender_addon...
【算法】移除元素
今天讲的是力扣题目的题解: 力扣题目: 72.移除元素 题目描述: 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不…...
【后端面试总结】设计一个分布式锁需要考虑哪些东西
分布式锁是我们在分布式场景中经常用到的一种技术,在后端面试中也是出镜率很高,那么我们设计分布式锁的时候应该从那几方面去考虑呢 实现分布式锁需要考虑的点 设置超时时间 设置超时时间的目的是为了避免这个场景:进程A拿了锁,…...
awr报告无法生成:常见案例与解决办法
awr报告无法生成:常见案例与解决办法 STATISTICS_LEVEL设置过低数据库打开状态不对主库隐含参数设置错误MMON子进程被SuspendSYS模式统计信息过期WRH$_SQL_PLAN表数据量太大AWR绑定变量信息收集超时撞上数据库Bug 9040676STATISTICS_LEVEL设置过低 STATISTICS_LEVEL设置为BAS…...
Hadoop 生态之 kerberos
参考链接 https://winway.github.io/2022/04/02/kerberos-ranger/ https://ieevee.com/tech/2016/06/22/ranger-2.html kerberos解决”who are you“的问题 ranger解决”what you can do“的问题 LDAP 轻型目录访问协议(英文:Lightweight Director…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
