力扣第23题:合并K个升序链表

详解力扣第23题:合并K个升序链表

题目描述

给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

本题可以通过优先队列-最小堆来高效解决,因为我们需要频繁地找到当前K个链表中值最小的元素,并进行合并。

最小堆思路

最小堆是一种完全二叉树结构,可以在O(logK) 的时间复杂度内完成插入和删除操作,适用于需要频繁寻找最小值的场景。对于本题,使用最小堆可以有效减少每次查找最小节点的时间,从而加速链表合并的过程。

代码详解

1. 数据结构定义

我们使用链表节点(ListNode)结构来表示输入的链表。MinHeap 结构用于实现最小堆。

#include <stdio.h>
#include <stdlib.h>// 定义链表结构体
struct ListNode {int val;struct ListNode *next;
};// 定义最小堆的结构体
struct MinHeap {struct ListNode **array;int size;
};
  • ListNode:链表节点,val 存储节点值,next 指向下一个节点。
  • MinHeap:最小堆,array 存储指向链表节点的指针数组,size 表示堆中节点的数量。

2. 创建最小堆

// 创建一个新的最小堆节点
struct MinHeap* createMinHeap(int k) {struct MinHeap* heap = (struct MinHeap*)malloc(sizeof(struct MinHeap));heap->array = (struct ListNode**)malloc(k * sizeof(struct ListNode*));heap->size = 0;return heap;
}

3. 堆操作

上浮操作
// 将堆元素进行上浮
void heapifyUp(struct MinHeap* heap, int idx) {while (idx > 0 && heap->array[(idx - 1) / 2]->val > heap->array[idx]->val) {struct ListNode* temp = heap->array[idx];heap->array[idx] = heap->array[(idx - 1) / 2];heap->array[(idx - 1) / 2] = temp;idx = (idx - 1) / 2;}
}

上浮操作用于插入元素时保持最小堆的性质,将新元素与父节点比较,并逐步上移至合适的位置。

下沉操作
// 将堆元素进行下沉
void heapifyDown(struct MinHeap* heap, int idx) {int smallest = idx;int left = 2 * idx + 1;int right = 2 * idx + 2;if (left < heap->size && heap->array[left]->val < heap->array[smallest]->val) {smallest = left;}if (right < heap->size && heap->array[right]->val < heap->array[smallest]->val) {smallest = right;}if (smallest != idx) {struct ListNode* temp = heap->array[idx];heap->array[idx] = heap->array[smallest];heap->array[smallest] = temp;heapifyDown(heap, smallest);}
}

下沉操作用于删除最小元素后保持堆的性质,将最后一个元素移动到根节点后,通过下沉操作恢复最小堆。

插入与删除最小元素
// 向堆中插入新元素
void insertMinHeap(struct MinHeap* heap, struct ListNode* node) {heap->array[heap->size] = node;heapifyUp(heap, heap->size);heap->size++;
}// 从堆中取出最小元素
struct ListNode* extractMin(struct MinHeap* heap) {struct ListNode* root = heap->array[0];heap->array[0] = heap->array[heap->size - 1];heap->size--;heapifyDown(heap, 0);return root;
}

4. 合并K个链表

// 合并K个升序链表
struct ListNode* mergeKLists(struct ListNode** lists, int k) {struct MinHeap* heap = createMinHeap(k);for (int i = 0; i < k; i++) {if (lists[i] != NULL) {insertMinHeap(heap, lists[i]);}}struct ListNode dummy;struct ListNode* tail = &dummy;dummy.next = NULL;while (heap->size > 0) {struct ListNode* minNode = extractMin(heap);tail->next = minNode;tail = tail->next;if (minNode->next != NULL) {insertMinHeap(heap, minNode->next);}}return dummy.next;
}

在这里,我们将每个链表的第一个节点插入最小堆中,每次取出堆中的最小节点,将其插入到最终合并后的链表中,并将该节点的下一个节点继续插入堆中。

5. 测试代码

// 创建新节点
struct ListNode* createNode(int val) {struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));newNode->val = val;newNode->next = NULL;return newNode;
}// 打印链表
void printList(struct ListNode* head) {while (head != NULL) {printf("%d ", head->val);head = head->next;}printf("\n");
}// 主函数
int main() {// 创建测试用例:[[1,4,5],[1,3,4],[2,6]]struct ListNode* list1 = createNode(1);list1->next = createNode(4);list1->next->next = createNode(5);struct ListNode* list2 = createNode(1);list2->next = createNode(3);list2->next->next = createNode(4);struct ListNode* list3 = createNode(2);list3->next = createNode(6);struct ListNode* lists[] = {list1, list2, list3};// 合并链表struct ListNode* result = mergeKLists(lists, 3);// 打印结果printf("合并后的链表: ");printList(result);return 0;
}

输出结果:

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

最小堆插入与删除操作图解

1. 初始状态

假设我们有三个链表,每个链表的第一个元素分别是 112,插入最小堆的初始状态如下:

        1/ \1   2

2. 删除最小元素

当我们删除堆顶最小元素(值为1)时,将 2 替换到根节点,进行下沉操作:

        1/ \2

继续从对应链表插入下一个节点,重复此过程直到所有链表都被合并。


通过最小堆实现,合并 K 个升序链表的时间复杂度为 O(NlogK),其中 N 是所有链表的节点总数,K 是链表的个数。

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

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

相关文章

银行客户贷款行为数据挖掘与分析

#1024程序员节 | 征文# 在新时代下&#xff0c;消费者的需求结构、内容与方式发生巨大改变&#xff0c;企业要想获取更多竞争优势&#xff0c;需要借助大数据技术持续创新。本文分析了传统商业银行面临的挑战&#xff0c;并基于knn、逻辑回归、人工神经网络三种算法&#xff0…

2024 10.25 判断一个矩阵是否对称

主对角线对称 思路&#xff1a;a[i][j]!a[j][i] 第一行和第一列顺序比较&#xff0c;后面依次类推 #include <stdio.h>int main(){int n,m;scanf("%d",&n);int a[n][n];for(int i0;i<n;i){for(int j0;j<n;j)scanf("%d",&a[i][j]);}i…

Spring Boot框架下中小企业设备管理系统开发

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理中小企业设备管理系统的相关信息成为必然。…

python的Django的render_to_string函数和render函数模板的使用

一、render_to_string render_to_string 是 Django 框架中的一个便捷函数&#xff0c;用于将模板渲染为字符串。 render_to_string(template_name.html, context, requestNone, usingNone) template_name.html&#xff1a;要渲染的模板文件的名称。context&#xff1a;传递给…

epub转为txt

使用Python通过ebooklib和BeautifulSoup等库将epub文件转换为txt文件。下 1.安装必要的依赖库&#xff1a; pip install ebooklib beautifulsoup4 lxmlimport ebooklib from ebooklib import epub from bs4 import BeautifulSoup import os# 读取epub文件并转换为txt文件 def …

新手入门之高级maven

文章目录 前言一、分模块设计与开发Maven 分模块设计的优势Maven 分模块设计的基本结构Maven 分模块项目的构建 二、继承与聚合三种打包方式&#xff1a;Maven 父模块和子模块的关系Maven 中的版本锁定1.<dependencyManagement> 标签主要特点&#xff1a; 2.使用 <pro…

刷题 - 图论

1 | bfs/dfs | 网格染色 200. 岛屿数量 访问到马上就染色&#xff08;将visited标为 true)auto [cur_x, cur_y] que.front(); 结构化绑定&#xff08;C17&#xff09;也可以不使用 visited数组&#xff0c;直接修改原始数组时间复杂度: O(n * m)&#xff0c;最多将 visited 数…

基于GPT的智能客服落地实践

&#x1f4cd;前言 在日常生活中&#xff0c;「客服」这个角色几乎贯穿着我们生活的方方面面。比如&#xff0c;淘宝买东西时&#xff0c;需要客服帮你解答疑惑。快递丢失时&#xff0c;需要客服帮忙找回。报名参加培训课程时&#xff0c;需要客服帮忙解答更适合的课程…… 基…

重构商业生态:DApp创新玩法与盈利模式的深度剖析

随着区块链技术的发展&#xff0c;DApp&#xff08;去中心化应用&#xff09;正在从实验走向成熟。DApp以去中心化、透明性和不可篡改性为基础&#xff0c;结合智能合约&#xff0c;逐步改变传统商业运作模式&#xff0c;创造新的市场生态。本文将从DApp的独特优势、创新玩法和…

找不到包的老版本???scikit-learn,numpy,scipy等等!!

废话不多说 直接上链接了&#xff1a; https://pypi.tuna.tsinghua.edu.cn/simple/https://pypi.tuna.tsinghua.edu.cn/simple/https://pypi.tuna.tsinghua.edu.cn/simple/xxx/ 后面的这个xxx就是包的名字 大家需要什么包的版本&#xff0c;直接输进去就可以啦 举个栗子&#…

【汇编语言】第一个程序(一)—— 一个源程序从写出到执行的过程

文章目录 前言1. 第一步&#xff1a;编写汇编源程序2. 第二步&#xff1a;对源程序进行编译连接3. 第三步&#xff1a;执行可执行文件中的程序结语 前言 &#x1f4cc; 汇编语言是很多相关课程&#xff08;如数据结构、操作系统、微机原理&#xff09;的重要基础。但仅仅从课程…

9. JSON RPC 服务

① JSON RPC 是一种基于 JSON 格式的轻量级的 RPC 协议标准,易于使用和阅读。 ② 在 Hyperf 里由 hyperf/json-rpc 组件来实现,可自定义基于 HTTP 协议来传输,或直接基于 TCP 协议来传输。 一、服务中心 目前 Hyperf 仅支持两种服务中心的组件支持: consul、nacosconsul 安…

了解 .NET 8 中的定时任务或后台服务:IHostedService 和 BackgroundService

IHostedService.NET 8 引入了使用和管理后台任务的强大功能BackgroundService。这些服务使长时间运行的操作&#xff08;例如计划任务、后台处理和定期维护任务&#xff09;可以无缝集成到您的应用程序中。本文探讨了这些新功能&#xff0c;并提供了实际示例来帮助您入门。您可…

物联网海量数据下的时序数据库选型:InfluxDB、TDEngine、MongoDB与HBase对比与建议

随着物联网&#xff08;IoT&#xff09;的普及&#xff0c;各行业纷纷部署大量传感器、设备生成的数据流&#xff0c;面对如此海量的时间序列数据&#xff0c;如何高效存储、查询和分析成为关键。为此&#xff0c;时序数据库&#xff08;Time Series Database, TSDB&#xff09…

react项目因eslint检测未通过而Failed to compile编译失败

环境 node v16.20.2react 18.3.1react-scripts 4.0.3 .eslintrc.json 配置&#xff1a; {"env": {"browser": true,"es6": true,"node": true},"settings": {"react": {"pragma": "React"…

Java应用程序的测试覆盖率之设计与实现(四)-- jacoco-maven-plugin

说在前面的话 加载jacocoagent,开始采集覆盖率数据。 java -javaagent:doc/jacocoagent.jar=includes=com.jacoco.*,output=tcpserver,port=7195,address=172.27.3.242,classdumpdir=classdumpdir/classes/ \ -jar target/jacoco-test-sample.jar. ____ _ …

Visual Studio配置tinyfiledialogs

下载地址&#xff1a;github下载链接 将下载的文件解压后&#xff0c;打开VS添加现有项 将.c文件添加进去 然后将tinyfiledialogs.h文件路径添加到包含目录 使用时包含头文件即可&#xff1a; #include <tinyfiledialogs.h>

上海亚商投顾:沪指缩量震荡 风电、传媒股集体走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 市场全天缩量震荡&#xff0c;三大指数集体收涨&#xff0c;北证50则跌超7%&#xff0c;超80只北交所个股跌逾…

2FA-双因素认证

双因素认证&#xff08;2FA&#xff0c;Two-Factor Authentication&#xff09;是一种提高安全性的方法&#xff0c;要求用户在登录或进行某些敏感操作时提供两种不同类型的身份验证信息。这种方法通过引入第二层验证&#xff0c;增加了账户被未经授权访问的难度。 项目结构 …

一文搞定图

图 图 常见类型与术语 图的表示 邻接矩阵 邻接表 基础操作 基于邻接矩阵的实现 基于邻接表的实现 遍历 广度优先 深度优先 图 图 是一种非线性数据结构&#xff0c;由 顶点 和 边 组成。 相较于线性关系的链表和分治关系的树&#xff0c;网络关系的图自由度更高 常见…