【C++】LeetCode:LCR 078. 合并 K 个升序链表

news2024/12/26 23:05:44

题干:

给定一个链表数组,每个链表都已经按升序排列。

请将所有链表合并到一个升序链表中,返回合并后的链表。
 

解法:优先队列

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
 auto cmp = [](ListNode*a,ListNode*b){
    return a->val>b->val;
};
class Solution {
public:
         ListNode * mergeTwoLists(ListNode * a,ListNode * b){
            ListNode * dummy = new ListNode(0);
            ListNode * cur = dummy;
            while (a!= nullptr&&b!= nullptr){
                if (a->val<b->val){
                    cur->next = a;
                    a = a->next;
                } else{
                    cur->next = b;
                    b = b->next;
                }
                cur = cur->next;
            }
            cur->next = (a== nullptr)?b:a;
            return dummy->next;
        };

        ListNode *mergeKLists(std::vector<ListNode*>& lists){

            std::priority_queue<ListNode*,std::vector<ListNode*>, decltype(cmp)> minHeap(cmp);

            for (auto list:lists) {
                if(list!= nullptr){
                    minHeap.push(list);
                }
            }

            ListNode dummy = ListNode(0);
            ListNode * tail = &dummy;

            while (!minHeap.empty()){
                ListNode * miniNode = minHeap.top();
                minHeap.pop();

                tail->next = miniNode;
                tail = tail->next;

                if (miniNode->next!= nullptr){
                    minHeap.push(miniNode->next);
                }
            }
            return  dummy.next;
        };
};

举例分步解析:

示例:合并三个升序链表

假设我们有三个升序链表:

  1. 链表 11 -> 4 -> 5
  2. 链表 21 -> 3 -> 4
  3. 链表 32 -> 6

初始化状态:

最小堆的基本概念

  • 最小堆 是一种特殊的二叉树结构,其中每个节点的值都小于或等于其子节点的值。
  • 堆顶(即根节点)是整个堆中最小的元素。
  • 最小堆通常用于实现优先队列,因为它可以在 O(log n) 时间内插入和删除元素,并且可以在 O(1) 时间内访问最小元素。

我们的目标是将这三个链表合并成一个升序链表。为了实现这一点,我们可以使用最小堆来高效地找到当前所有链表中值最小的节点。

初始状态

在开始时,我们将每个链表的头节点加入最小堆。此时,最小堆的状态如下:

  • 堆顶 是 1,它来自链表 1 或链表 2(因为我们有两个 1)。
  • 堆的其他节点分别是链表 2 的头节点 1 和链表 3 的头节点 2
第一步:取出堆顶元素

我们从堆中取出最小的元素 1(来自链表 1),并将其加入结果链表。然后,我们将链表 1 的下一个节点 4 加入堆中。此时,堆的状态变为:

  • 堆顶 现在是 1,它来自链表 2。
  • 堆的其他节点分别是链表 1 的下一个节点 4 和链表 3 的头节点 2
第二步:再次取出堆顶元素

我们从堆中取出最小的元素 1(来自链表 2),并将其加入结果链表。然后,我们将链表 2 的下一个节点 3 加入堆中。此时,堆的状态变为:

  • 堆顶 现在是 2,它来自链表 3。
  • 堆的其他节点分别是链表 1 的下一个节点 4 和链表 2 的下一个节点 3
第三步:继续取出堆顶元素

我们从堆中取出最小的元素 2(来自链表 3),并将其加入结果链表。然后,我们将链表 3 的下一个节点 6 加入堆中。此时,堆的状态变为:

  • 堆顶 现在是 3,它来自链表 2。
  • 堆的其他节点分别是链表 1 的下一个节点 4 和链表 3 的下一个节点 6
第四步:继续取出堆顶元素

我们从堆中取出最小的元素 3(来自链表 2),并将其加入结果链表。然后,我们将链表 2 的下一个节点 4 加入堆中。此时,堆的状态变为:

  • 堆顶 现在是 4,它来自链表 1。
  • 堆的其他节点分别是链表 2 的下一个节点 4 和链表 3 的下一个节点 6
第五步:继续取出堆顶元素

我们从堆中取出最小的元素 4(来自链表 1),并将其加入结果链表。堆的状态变为:

  • 堆顶 现在是 4,它来自链表 2。
  • 堆的其他节点是链表1的下一节点5,链表 3 的下一个节点 6
第六步:继续取出堆顶元素

我们从堆中取出最小的元素 4(来自链表 2),并将其加入结果链表。此时,链表 2 已经遍历完毕,没有更多的节点可以加入堆中。

堆的状态变为:堆顶 现在是 5,它来自链表 1,其他节点是6来自链表3。

第七步:继续取出堆顶元素

我们从堆中取出元素 5,并将其加入结果链表。

第八步:继续取出堆顶元素

我们从堆中取出元素 6,并将其加入结果链表。

最终结果

合并后的链表为:1 -> 1 -> 2 -> 3 -> 4 -> 4 -> 5 -> 6

时间复杂度分析

初始化最小堆
  • 操作:将 k 个链表的头节点插入最小堆。
  • 复杂度:每次插入操作的时间复杂度是 O(log⁡k),因此初始化堆的时间复杂度为 O(klog⁡k)。
提取最小元素和插入新元素
  • 操作:每次从堆中提取最小元素并插入新的节点。
  • 复杂度:每次提取最小元素和插入新元素的操作时间复杂度均为 O(log⁡k)。
  • 次数:总共需要进行 N 次提取和插入操作(因为总共有 N 个节点)。
  • 总复杂度:O(Nlog⁡k)

总时间复杂度

  • 初始化堆:O(klog⁡k)
  • 提取和插入操作:O(Nlog⁡k)

因此,总的时间复杂度为: O(klog⁡k+Nlog⁡k)

由于 klog⁡k在大多数情况下远小于 Nlog⁡k,通常可以简化为: O(Nlog⁡k)

空间复杂度分析

  • 最小堆:堆中最多包含 k 个节点(即每个链表的当前最小节点)。
  • 结果链表:需要额外的空间来存储合并后的链表,但这是输出的一部分,不计入额外空间复杂度。

因此,空间复杂度主要由最小堆决定,为: O(k)

总结

  • 时间复杂度:O(Nlog⁡k)
  • 空间复杂度:O(k)

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

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

相关文章

数据结构和算法-04二叉树-04

广度优先的实现力扣中常见的二叉树相关问题及基本解决方案 tips&#xff1a; 在解决问题时&#xff0c;先确保问题能解决&#xff0c;再去考虑效率&#xff0c;这是解题的关键&#xff0c;切不可为追求效率而变成了技巧性解答。 广度优先 广度优先(层序遍历)遍历的方式是按层次…

DMA代码部分

第一个程序的接线图 OLED ShowHexNum(2,1,(uint32_t)&ADC1->DR,8); 这样可以看AD的DR寄存器的的地址(固定的)了 可以跑一下然后和手册对比 先查ADC1的地址 再在外设的总表里面, 查一下DR相对于上面地址的偏移量 所以其地址为4001 244C 研究一下外设寄存器的地址是怎么…

spdlog高性能日志系统

spdlog高性能日志系统 spdlog 是一个快速、简单、功能丰富的 C 日志库&#xff0c;专为现代 C 开发设计。它支持多种日志后端&#xff08;如控制台、文件、syslog 等&#xff09;&#xff0c;并提供灵活的格式化和线程安全的日志输出。 1. 特点 极高的性能&#xff1a;大量的编…

FPGA在线升级 -- Multiboot

简介 本章节主要描述关于如何从Golden Image转换到Multiboot Image程序。 升级方案 Golden Image转换到Multiboot Image的方法主要又两种 1、使用ICAPE2 原语&#xff1b; 2、在XDC文件中加入升级约束命令&#xff1b; 以上两种方案都可以实现在线升级&#xff0c;第一种升级…

守护进程化

目录 一、进程组 二、会话 &#xff08;1&#xff09;什么是会话 &#xff08;2&#xff09;如何创建一个会话 三、守护进程 一、进程组 之前我们学习过进程&#xff0c;其实每一个进程除了有一个进程 ID(PID)之外 还属于一个进程组。进程组是一个或者多个进程的集合&…

QML插件扩展

https://note.youdao.com/ynoteshare/index.html?id294f86c78fb006f1b1b78cc430a20d74&typenote&_time1706510764806

RabbitMQ七种工作模式之 RPC通信模式, 发布确认模式

文章目录 六. RPC(RPC通信模式)客户端服务端 七. Publisher Confirms(发布确认模式)1. Publishing Messages Individually(单独确认)2. Publishing Messages in Batches(批量确认)3. Handling Publisher Confirms Asynchronously(异步确认) 六. RPC(RPC通信模式) 客⼾端发送消息…

ArcGIS字符串补零与去零

我们有时候需要 对属性表中字符串的补零与去零操作 我们下面直接视频教学 下面看视频教学 ArcGIS字符串去零与补零 推荐学习 ArcGIS全系列实战视频教程——9个单一课程组合 ArcGIS10.X入门实战视频教程&#xff08;GIS思维&#xff09; ArcGIS之模型构建器&#xff08;Mod…

前端面试如何出彩

1、原型链和作用域链说不太清&#xff0c;主要表现在寄生组合继承和extends继承的区别和new做了什么。2、推荐我的两篇文章&#xff1a;若川&#xff1a;面试官问&#xff1a;能否模拟实现JS的new操作符、若川&#xff1a;面试官问&#xff1a;JS的继承 3、数组构造函数上有哪些…

大模型应用编排工具Dify之构建专属FQA应用

1.前言 ​ 通过 dify可以基于开源大模型的能力&#xff0c;并结合业务知识库、工具API和自定义代码等构建特定场景、行业的专属大模型应用。本文通过 dify工作室的聊天助手-工作流编排构建了一个基于历史工作日志回答问题的助手&#xff0c;相比原始的大模型答复&#xff0c;通…

前端node环境安装:nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)

需求&#xff1a;在做前端开发的时候&#xff0c;有的时候 这个项目需要 node 14 那个项目需要 node 16&#xff0c;我们也不能卸载 安装 。这岂不是很麻烦。这个时候 就需要 一个工具 来管理我们的 node 版本和 npm 版本。 下面就分享一个 nvm 工具 用来管理 node 版本。 这个…

c基础加堆练习题

1】思维导图&#xff1a; 2】在堆区空间连续申请5个int类型大小空间&#xff0c;用来存放从终端输入的5个学生成绩&#xff0c;然后显示5个学生成绩&#xff0c;再将学生成绩升序排序&#xff0c;排序后&#xff0c;再次显示学生成绩。显示和排序分别用函数完成 要求&#xff…

嵌入式Linux 设备树 GPIO详解 示例分析 三星 NXP RK

GPIO设备树用于在Linux内核中定义与GPIO相关的硬件资源&#xff0c;它使操作系统可以识别、配置和使用GPIO引脚。设备树中通常会指定GPIO控制器的基地址、GPIO引脚的中断配置、时钟和其他相关信息。 目录 RK相关案例代码 NXP相关案例代码 三星相关案例代码 在设备树中&…

【日记】不想随礼欸(926 字)

正文 今天忙了一天。感觉从早上就开始在救火。客户经理迎接检查&#xff0c;要补资料&#xff0c;找我们问这样要那样&#xff0c;我自己的事情几乎完全开展不了。虽说也没什么大事就是了。 晚上行长还让我重装系统…… 难绷。看来这个爹味新行长懂得还挺多。 中午趁着不多的休…

Spring 源码学习(七)——注解后处理器

通过之前对注解式配置的解析&#xff08;Spring 源码学习&#xff08;三&#xff09;—— 注解式配置解析_spring源码学习-CSDN博客&#xff09;可以发现其使用 AnnotationConfigUtils 类的 registerAnnotationConfigProcessors 静态方法对象注解后处理器对象进行注册&#xff…

如何避免缓存击穿?超融合常驻缓存和多存储池方案对比

作者&#xff1a;SmartX 解决方案专家 钟锦锌 很多运维人员都知道&#xff0c;混合存储介质配置可能会带来“缓存击穿”的问题&#xff0c;尤其是大数据分析、数据仓库等需要频繁访问“冷数据”的应用场景&#xff0c;缓存击穿可能会更频繁地出现&#xff0c;影响业务运行。除…

Scala的正则表达式二

验证用户名是否合法 规则 1.长度在6-12之间 2.不能数字开头 3.只能包含数字&#xff0c;大小写字母&#xff0c;下划线def main(args: Array[String]): Unit {val name1 "1admin"//不合法&#xff0c;是数字开头val name2 "admin123"//合法val name3 &quo…

【CKA】Kubernetes(k8s)认证之CKA考题讲解

CKA考题讲解 0.考试101 0.1 kubectl命令⾃动补全 在 bash 中设置当前 shell 的⾃动补全&#xff0c;要先安装 bash-completion 包。 echo "source <(kubectl completion bash)" >> ~/.bashrc还可以在补全时为 kubectl 使⽤⼀个速记别名&#xff1a; al…

导入kotlin

android studio 导入kotlin项目 android studio kotlin教程 或者直接拿一个kt文件进来&#xff0c;在顶部会显示一个config&#xff0c;然后设置version&#xff0c;点击OK就可以了自动导了

《CSS 知识点》大屏卡片布局思路:弹性布局 flex-grow

思路 大屏左右两侧高宽一致&#xff0c;内部卡片可按比例设置&#xff01; 使用弹性布局和属性 flex-grow 设置比例&#xff1b;间隔使用 margin-bottom 设置&#xff0c;最后一个卡片不设置&#xff1b; 效果如图 代码说明 CSS代码 26 - 30&#xff0c;左右两侧设置弹性布…