坚持刷题|合并有序链表
文章目录
- 题目
- 思考
- 代码实现
- 迭代
- 递归
- 扩展
- 实现k个有序链表合并
- 方法一
- 方法二
- PriorityQueue
- 基本操作
- Java示例
- 注意事项
Hello,大家好,我是阿月。坚持刷题,老年痴呆追不上我,消失了一段时间,我又回来刷题啦,今天先刷个简单的:合并有序链表
题目
21. 合并两个有序链表
思考
合并有序链表这一算法问题主要考察以下几个关键点
- 链表操作:理解链表数据结构以及如何遍历、比较、连接链表节点。
- 边界条件处理:包括处理一个或两个链表为空的情况,以及其中一个链表先到达末尾的场景。
- 递归与迭代:可以选择递归或迭代的方法来解决问题,每种方法都有其优缺点,需要理解何时使用哪一种。
- 效率考量:优化算法的时间复杂度和空间复杂度,例如使用优先队列可以达到较好的时间性能。
- 代码整洁性:写出清晰、可读性强的代码,避免不必要的复杂性和冗余。
- 错误处理:在实际编码中,考虑到可能出现的异常情况,比如处理
null
指针异常。 - 算法设计:理解不同算法策略,如两两合并法、使用辅助数据结构等。
- 优化技巧:了解如何在不增加额外空间复杂度的情况下解决问题,例如原地修改链表而非创建新的链表。
- 测试用例:编写全面的测试用例验证代码的正确性,包括极端情况和常见情况。
- 性能分析:能够分析和解释算法的时间和空间复杂度,理解为什么某种方法优于其他方法。
代码实现
合并两个有序链表是一个常见的链表操作,可以通过迭代或递归的方式实现。
迭代
public class ListNode {int val;ListNode next;ListNode(int x) { val = x; }
}public class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(0);ListNode current = dummy;while (l1 != null && l2 != null) {if (l1.val < l2.val) {current.next = l1;l1 = l1.next;} else {current.next = l2;l2 = l2.next;}current = current.next;}current.next = l1 == null ? l2 : l1;return dummy.next;}
}
在这段代码中,我们首先创建一个虚拟头节点dummy
和一个指针cur
指向dummy
。然后我们遍历两个链表,每次都把较小的节点接到cur
的后面,并移动cur
和较小节点所在链表的头指针。当一个链表遍历完后,我们就直接把另一个链表接到cur
的后面。最后返回dummy.next
就是合并后的链表。
递归
使用递归的方式来合并两个有序链表是一种直观且简洁的方法。以下是使用Java实现的示例代码:
public class ListNode {int val;ListNode next;ListNode(int x) { val = x; }
}public class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {if (l1 == null) {return l2;}if (l2 == null) {return l1;}if (l1.val < l2.val) {l1.next = mergeTwoLists(l1.next, l2);return l1;} else {l2.next = mergeTwoLists(l1, l2.next);return l2;}}
}
在上述代码中,mergeTwoLists
方法接受两个链表的头节点l1
和l2
作为参数。该方法首先检查两个链表是否为空。如果其中一个链表为空,那么就直接返回另一个链表,因为这意味着另一个链表已经是合并后的结果。
如果两个链表都不为空,那么就比较两个链表头节点的值。如果l1
的值小于l2
的值,那么就将l1
的next
字段设置为l1.next
和l2
合并的结果,然后返回l1
。反之亦然,如果l2
的值小于等于l1
的值,那么就将l2
的next
字段设置为l1
和l2.next
合并的结果,然后返回l2
。
这种方法利用了递归的特性,逐步将大问题分解成小问题,直到问题简单到可以直接解决(即一个链表为空)。由于递归的深度最多为链表的长度,因此这种方法的时间复杂度为O(n),其中n为两个链表中节点的总数。
扩展
实现k个有序链表合并
方法一
我们可以使用分治的策略,将K个链表两两合并,直到剩下最后一个链表。这就是所谓的"两两合并"策略。以下是使用Java实现的代码:
public class ListNode {int val;ListNode next;ListNode(int x) { val = x; }
}public class Solution {public ListNode mergeKLists(ListNode[] lists) {int amount = lists.length;if(amount==0){return null;}int interval = 1;while (interval < amount) {for (int i = 0; i < amount - interval; i += interval * 2) {lists[i] = mergeTwoLists(lists[i], lists[i + interval]);}interval *= 2;}return lists[0];}private ListNode mergeTwoLists(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(0);ListNode current = dummy;while (l1 != null && l2 != null) {if (l1.val < l2.val) {current.next = l1;l1 = l1.next;} else {current.next = l2;l2 = l2.next;}current = current.next;}current.next = l1 == null ? l2 : l1;return dummy.next;}
}
在这个代码中,我们首先定义了一个mergeTwoLists
方法用于合并两个有序链表。然后在mergeKLists
方法中,我们使用了"两两合并"的策略来合并K个有序链表。
这种方法的时间复杂度为O(N log K),其中N是所有链表中节点的总数,K是链表的数量。空间复杂度为O(1)。
方法二
在Java中,我们还可以使用 PriorityQueue 来实现。
import java.util.PriorityQueue;public class ListNode {int val;ListNode next;ListNode(int x) { val = x; }
}public class Solution {public ListNode mergeKLists(ListNode[] lists) {PriorityQueue<ListNode> queue = new PriorityQueue<>((a, b) -> a.val - b.val);ListNode dummy = new ListNode(0);ListNode tail = dummy;for (ListNode node : lists) {if (node != null) {queue.add(node);}}while (!queue.isEmpty()) {ListNode node = queue.poll();tail.next = node;tail = tail.next;if (node.next != null) {queue.add(node.next);}}return dummy.next;}
}
在这个解决方案中,我们首先创建一个虚拟头节点和一个尾节点,然后遍历所有的链表,将每个链表的头节点放入优先队列中。然后我们开始循环处理优先队列,每次从队列中取出最小的元素,将其添加到结果链表中,然后将其下一个节点(如果存在)放入队列中。最后返回虚拟头节点的下一个节点,即为合并后的链表的头节点。
- 注意,Java中的 PriorityQueue 默认是按照自然顺序排序的,所以我们需要提供一个比较器来确保按照节点的值进行排序。
PriorityQueue
是Java集合框架的一部分,它是一个基于优先堆的无界优先队列。此队列按照元素的自然排序进行排序,或者根据构造队列时提供的Comparator进行排序,具体取决于使用的构造方法。
PriorityQueue
最小堆是一种特殊的完全二叉树结构,其中每个父节点的值都小于或等于其子节点的值。这种结构保证了堆的根节点始终是最小的元素,从而使得查找最小元素的操作非常快速。最小堆在Java中可以通过java.util.PriorityQueue
类来实现,因为这个类内部就是使用数组实现的最小堆。
基本操作
- 插入元素 (
offer
或add
):将一个元素添加到堆中,同时保持堆的性质不变,但是当队列已满时,add会抛出异常,而offer则返回false。 - 删除最小元素 (
poll
):从堆中移除并返回最小的元素。 - 获取最小元素 (
peek
):返回但不移除最小的元素。 - 移除并返回队列头部的元素(remove):如果队列为空,则抛出NoSuchElementException异常。
Java示例
首先,我们创建一个PriorityQueue
实例,这将作为我们的最小堆:
import java.util.PriorityQueue;public class MinHeapExample {public static void main(String[] args) {// 创建一个最小堆PriorityQueue<Integer> minHeap = new PriorityQueue<>();// 插入元素minHeap.offer(5);minHeap.offer(1);minHeap.offer(3);minHeap.offer(4);System.out.println("堆中的元素:" + minHeap);// 获取最小元素Integer smallest = minHeap.peek();System.out.println("最小元素是:" + smallest);// 删除最小元素Integer removed = minHeap.poll();System.out.println("删除的最小元素:" + removed);System.out.println("删除后堆中的元素:" + minHeap);}
}
运行上述代码,你将看到如下输出:
堆中的元素:[1, 4, 3, 5]
最小元素是:1
删除的最小元素:1
删除后堆中的元素:[3, 4, 5]
注意事项
PriorityQueue
默认情况下实现的是最小堆,如果要实现最大堆,可以自定义比较器Comparator
。PriorityQueue
不允许插入null
元素,否则会抛出NullPointerException
。PriorityQueue
没有固定大小,它可以动态调整大小。- 通过上面的示例,可以看到
PriorityQueue
如何在内部自动维护堆的性质,使得最小元素始终位于堆的顶部,方便我们进行高效的查找和删除操作。 PriorityQueue
的一个重要特性是它的元素必须是可比较的,也就是说,它们必须实现了Comparable接口,或者在创建PriorityQueue
时提供了一个Comparator。
例如,下面的代码创建了一个按照字符串长度排序的PriorityQueue
:
PriorityQueue<String> pq = new PriorityQueue<>(new Comparator<String>() {public int compare(String s1, String s2) {return s1.length() - s2.length();}
});
在这个例子中,我们提供了一个Comparator,它将字符串按照长度进行排序。
相关文章:
![](https://img-blog.csdnimg.cn/direct/12337d5e7cad430f817476c1548e44ab.png)
坚持刷题|合并有序链表
文章目录 题目思考代码实现迭代递归 扩展实现k个有序链表合并方法一方法二 PriorityQueue基本操作Java示例注意事项 Hello,大家好,我是阿月。坚持刷题,老年痴呆追不上我,消失了一段时间,我又回来刷题啦,今天…...
![](https://img-blog.csdnimg.cn/direct/de893b40d7ae4686a6225f361c7c90fb.png)
SPI协议——对外部SPI Flash操作
目录 1. W25Q32JVSSIQ背景知识 1.1 64个可擦除块 1.2 1024个扇区(每个块有16个扇区) 1.3 页 1. W25Q32JVSSIQ背景知识 W25Q32JV阵列被组织成16,384个可编程页,每页有256字节。一次最多可以编程256个字节。页面可分为16组(4KB扇区清除&…...
![](https://img-blog.csdnimg.cn/direct/57eda91db89a4e1dad6aec7947cb7292.png)
kotlin类型检测与类型转换
一、is与!is操作符 1、使用 is 操作符或其否定形式 !is 在运行时检测对象是否符合给定类型。 fun main() {var a "1"if(a is String) {println("a是字符串类型:${a.length}")}// 或val b a is Stringprintln(b) } 二、"不安全的"转换操作符…...
![](https://www.ngui.cc/images/no-images.jpg)
【JDBC】Oracle数据库连接问题记录
Failed to load driver class oracle.jdbc.driver.OracleDriver in either of HikariConfig class oracle驱动包未正确加载,可以先尝试使用下面方式加载检查类是否存在,如果不存在需要手动下载odbc包 try {Class.forName("oracle.jdbc.driver.Ora…...
![](https://www.ngui.cc/images/no-images.jpg)
leetcode45 跳跃游戏II
题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n - 1]…...
![](https://www.ngui.cc/images/no-images.jpg)
【数学】什么是方法矩估计?和最大似然估计是什么关系?
背景 方法矩估计(Method of Moments Estimation)和最大似然估计(Maximum Likelihood Estimation, MLE)是两种常用的参数估计方法。方法矩估计基于样本矩与总体矩的关系,通过样本数据计算样本矩来估计总体参数。最大似…...
![](https://img-blog.csdnimg.cn/direct/75f0aa9650494a42b0ba4557dc826cde.png#pic_center)
C++初学者指南第一步---10.内存(基础)
C初学者指南第一步—10.内存(基础) 文章目录 C初学者指南第一步---10.内存(基础)1.内存模型1.1 纸上谈兵:C的抽象内存模型1.2 实践:内存的实际处理 2. 自动存储3.动态存储:std::vector3.1 动态内…...
![](https://www.ngui.cc/images/no-images.jpg)
扩散模型详细推导过程——编码与解码
符号表 符号含义 x ( i ) z 0 ( i ) \boldsymbol{x}^{(i)}\boldsymbol{z}_0^{(i)} x(i)z0(i)第 i i i个训练数据,其为长度为 d d d的向量 z t ( i ) \boldsymbol{z}_t^{(i)} zt(i)第 i i i个训练数据在第 t t t时刻的加噪版本 ϵ t ( i ) \boldsymbol{\epsilo…...
![](https://www.ngui.cc/images/no-images.jpg)
js如何实现开屏弹窗
开屏弹窗是什么,其实就是第一次登录后进入页面给你的一种公告提示,此后再回到当前这个页面时弹窗是不会再出现的。也就是说这个弹窗只会出现一次。 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>…...
![](https://www.ngui.cc/images/no-images.jpg)
C#——文件读取Directory类详情
文件读取Directory类 Durectory提供了目录以及子目录进行创建移动和列举操作方法 Directory和Directorylnfo类(主要操作文件目录属性列如文件是否隐藏的 或者只读等这些属性) Directory对目录进行复制、移动、重命名、创建和删除等操作DirectoryInfo用于对目录属性执行操作 …...
![](https://img-blog.csdnimg.cn/direct/a52743d573f745e4befd5744316879ce.png)
Ruby on Rails Post项目设置网站初始界面
在构建了Ruby的Web服务器后,第三步就可以去掉框架的官方页面,设置自己的网页初始页了。 Linux系统安装Ruby语言-CSDN博客 、在Ubuntu中创建Ruby on Rails项目并搭建数据库-CSDN博客、 Ruby语言建立Web服务器-CSDN博客 了解Ruby onRails项目中的主要文件…...
![](https://img-blog.csdnimg.cn/direct/8d85482617ed49518789a2da231ce984.png)
03-QTWebEngine中使用qtvirtualkeyboard
qt提供了 virtualKeyboard 虚拟键盘模块,只需要在在main函数中最开始加入这样一句就可以了 qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); 但是在使用的时候遇到了一些问题: 1、中文输入的时候没有输入提示 Qvirt…...
![](https://www.ngui.cc/images/no-images.jpg)
leetcode3无重复字符的最长字串(重点讲滑动窗口)
本文主要讲解无重复字符的最长字串的要点与细节,根据步骤一步步走更方便理解 c与java代码如下,末尾 具体要点: 1. 区分一下子串和子序列 子串:要求元素在母串中是连续地出现 子序列:不要求连续 2. 题目中有两个核心…...
![](https://img-blog.csdnimg.cn/direct/aa0b52391be54afdbc5b39f989f334d9.png)
Gobject tutorial 八
The GObject base class Object memory management Gobject的内存管理相关的API很复杂,但其目标是提供一个基于引用计数的灵活的内存管理模式。 下面我们来介绍一下,与管理引用计数相关的函数。 Reference Count 函数g_object_ref和g_object_unref的…...
![](https://img-blog.csdnimg.cn/img_convert/77a5bbfb274858f9c9e39e71406e104f.png#pic_center)
DDMA信号处理以及数据处理的流程---cfar检测
Hello,大家好,我是Xiaojie,好久不见,欢迎大家能够和Xiaojie一起学习毫米波雷达知识,Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程,本系列文章将从目标生成、信号仿真、测距、测速、cfar检测、测角、目标聚类、目标跟踪这几个模块逐步介绍,这个系列的…...
【机器学习】从理论到实践:决策树算法在机器学习中的应用与实现
📝个人主页:哈__ 期待您的关注 目录 📕引言 ⛓决策树的基本原理 1. 决策树的结构 2. 信息增益 熵的计算公式 信息增益的计算公式 3. 基尼指数 4. 决策树的构建 🤖决策树的代码实现 1. 数据准备 2. 决策树模型训练 3.…...
![](https://www.ngui.cc/images/no-images.jpg)
Zookeeper 集群节点故障剔除、切换、恢复原理
Zookeeper 集群节点故障剔除、切换、恢复原理 zookeeper 集群节点故障时,如何剔除节点,如果为领导节点如何处理,如何进行故障恢 复的,实现原理? 在 Zookeeper 集群中,当节点故障时,集群需要自动剔除故障节点并进行故障恢复,确保集群的高 可用性和一致性。具体来说,…...
![](https://www.ngui.cc/images/no-images.jpg)
解决帝国cms栏目管理拼音乱码的问题
帝国CMS7.5版本utf-8版网站后台增加栏目生成乱码的问题怎么解决 1、需要改一个函数,并且增加一个处理文件,方法如下: 修改e/class/connect.php文件,找到ReturnPinyinFun函数,如未修改文件在4533-4547行,将…...
![](https://img-blog.csdnimg.cn/direct/c8edbd5596224407bcbf4d35d2f85846.png)
Git快速入门
一 快速使用 1.1 初始化 什么是版本库呢?版本库又名仓库,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史࿰…...
![](https://www.ngui.cc/images/no-images.jpg)
【18.0】JavaScript---事件案例
【18.0】JavaScript—事件案例 【一】开关灯事件 【介绍】设置一个按钮,按下按钮触发事件,来回切换圆形图片的颜色 【分析】 图片设置:设置成圆形的图片背景颜色:设置红绿两个颜色,来回切换按钮设置:点击…...
![](https://img-blog.csdnimg.cn/direct/ff8640497e7d40b690caa19981a6c05e.png)
推荐系统三十六式学习笔记:原理篇.矩阵分解12|如果关注排序效果,那么这个模型可以帮到你
目录 矩阵分解的不足贝叶斯个性化排序AUC构造样本目标函数训练方法 总结 矩阵分解在推荐系统中的地位非常崇高。它既有协同过滤的血统,又有机器学习的基因,可以说是非常优秀了;但即便如此,传统的矩阵分解无论是在处理显式反馈&…...
![](https://www.ngui.cc/images/no-images.jpg)
Kafka之ISR机制的理解
文章目录 Kafka的基本概念什么是ISRISR的维护机制ISR的作用ISR相关配置参数同步过程示例代码总结 Kafka中的ISR(In-Sync Replicas同步副本)机制是确保数据高可用性和一致性的核心组件。 Kafka的基本概念 在Kafka中,数据被组织成主题…...
![](https://img-blog.csdnimg.cn/direct/25152a61a65a490c97aa516750ac97c8.png)
如何设计一个点赞系统
首先我们定义出一个点赞系统需要对外提供哪些接口: 1.用户对特定的消息进行点赞; 2.用户查看自己发布的某条消息点赞数量以及被哪些人赞过; 3.用户查看自己给哪些消息点赞过; 这里假设每条消息都有一个message_id, 每一个用户都…...
![](https://www.ngui.cc/images/no-images.jpg)
对象存储测试工具-s3cmd
一、环境安装 官网:https://s3tools.org/s3cmd 下载安装包:https://s3tools.org/download GitHub:https://github.com/s3tools/s3cmd/releases 本文安装包:https://github.com/s3tools/s3cmd/releases/download/v2.0.2/s3cmd-2.0…...
![](https://www.ngui.cc/images/no-images.jpg)
OpenCV--图像色彩空间及转换
图像色彩空间及转换 python代码和笔记 python代码和笔记 import cv2 色彩空间,基础:RGB或BGR OpenCV中: 一、HSV(HSB):用的最多, Hue:色相-色彩(0-360),红色:0,绿色&…...
![](https://img-blog.csdnimg.cn/direct/58268a0ab78e4fbeb99491dea2b7d19a.png)
RIP解决不连续子网问题
#交换设备 RIP解决不连续子网问题 一、不连续子网的概念 相同主网下的子网,被另一个主网分割,例如下面实验拓扑在某公司的网络整改项目中,原先R1 和RS 属于同一主网络 10.0.0.0/8,现被 R2、R3、R4 分离,整网采用了 …...
![](https://img-blog.csdnimg.cn/img_convert/c69912111f11a6c9faf8f347d34782f8.jpeg)
动态轮换代理IP是什么?有什么用?
如果您要处理多个在线帐户,选择正确的代理类型对于实现流畅的性能至关重要。但最适合这项工作的代理类型是什么? 为了更好地管理不同平台上的多个账户并优化成本,动态住宅代理IP通常作用在此。 一、什么是轮换代理? 轮换代理充当…...
![](https://www.ngui.cc/images/no-images.jpg)
MAC配置VScode中C++项目debug环境
文章目录 配置步骤问题解决Unable to start debugging. LLDB exited unexpectedly with exit code 137 (0x89). 配置步骤 在Mac上配置VS Code以进行C调试涉及几个步骤: 安装必要的工具: 确保您已经安装了Visual Studio Code和C插件。 检查是否安装了Clang…...
![](https://www.ngui.cc/images/no-images.jpg)
PostgreSQL源码分析——CREATE CAST
CREATE CAST源码分析 CREATE CAST用法 CREATE CAST —— 定义一个用户自定义的类型转换 用法如下: CREATE CAST (source_type AS target_type)WITH FUNCTION function_name [ (argument_type [, ...]) ][ AS ASSIGNMENT | AS IMPLICIT ]CREATE CAST (source_type…...
![](https://img-blog.csdnimg.cn/direct/1b87d057c6424b6da8a567cf74f9c335.jpeg)
解锁5G新营销:视频短信的优势与全方位推广策略
随着5G时代的全面来临,企业的数字化转型步伐日益加快,视频短信作为新兴的数字营销工具,正逐步展现出其巨大的潜力。视频短信群发以其独特的形式和内容,将图片、文字、视频、声音融为一体,为用户带来全新的直观感受&…...
![](/images/no-images.jpg)
做网站把自己做死/企业如何开展网络营销
http://mac.pcbeta.com/viewthread.php?tid7137&extrapage%3D1&page1&styleid5 编者按:风险投资家保罗格雷厄姆以其优秀的程序员素养以及对技术演进的深入思考而闻名,其参与创办的风险投资公司 Y Combinator 关注于为新创技术团队提供种子…...
燕窝网站怎么做/云南百度推广开户
整理 | 李雪敬出品 | 程序人生(ID:coder_life)据微博用户程序员的那些事 透露,一名来自洛阳的程序员在离职后的第二个月收到了原公司的汇款2400元,该笔汇款备注了竞业协议补偿款,在收到该笔汇款后不久&…...
![](/images/no-images.jpg)
wordpress外贸商店/长春seo技术
一。周六三月进去。星期天 Calendar calendarCalendar.getInstance();//当前日期Calendar calendar2Calendar.getInstance();int curYear calendar2.get(Calendar.YEAR); // 得到系统年份int curMonth calendar2.get(Calendar.MONTH); // 得到系统月份int curDaycalendar2.ge…...
![](/images/no-images.jpg)
长沙h5建站/长沙疫情最新消息
表单事件 onblur失焦 onfocus聚焦 onchange 失焦且改变元素内容 oninput 改变元素内容 onsubmit 提交时调用 onreset 重置调用 鼠标事件 onclick 单击事件ondbclick 双击事件onmouseout 鼠标移出时事件onmouseover 鼠标移入时触发onmouseenter 鼠标移入时触发onmouseleave 鼠标…...
![](https://images2015.cnblogs.com/blog/717936/201610/717936-20161022134626685-814465602.png)
网站开发从事/做销售最挣钱的10个行业
Gcc特点 Gcc基本用法 1、gcc的概念 GCC(GNU Compiler Collection,GNU编译器套装),是一款由GNU开发的编程语言编译器。GCC原名为GNU C 语言编译器,因为它原本只能处理C语言。GCC很快地扩展,变得可处理C。之后也变得可处理Fortran、…...
![](/images/no-images.jpg)
服装门户系统网站/全渠道营销的概念
最近更新的博客 华为 od 2023 | 什么是华为 od,od 薪资待遇,od 机试题清单华为 OD 机试真题大全,用 Python 解华为机试题 | 机试宝典【华为 OD 机试】全流程解析+经验分享,题型分享,防作弊指南华为 od 机试,独家整理 已参加机试人员的实战技巧本篇题目:停车找车位 or 停车…...