合并K个升序链表(LeetCode 23)

文章目录

  • 1.问题描述
  • 2.难度等级
  • 3.热门指数
  • 4.解题思路
    • 方法一:顺序合并
    • 方法二:分治合并
    • 方法三:使用优先队列合并
  • 参考文献

1.问题描述

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

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

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[1->4->5,1->3->4,2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

2.难度等级

Hard。

3.热门指数

★★★★☆

4.解题思路

方法一:顺序合并

我们可以想到一种最朴素的方法,依次将链表数组中的链表与最终结果合并。问题便退化成合并两个有序链表。

如何合并两个有序链表呢?

遍历两个链表选择值较小的结点链接到结果链表中即可。当一个节点被添加到结果链表之后,将对应链表中的节点向后移一位。

为了简化对结果链表边界条件的判断,可以引入哨兵结点。哨兵结点的 Next 指针便是结果链表的头结点。

遍历 list1 或 list2 链表,选择 list1 与 list2 链表当前结点值较小的结点,挂接到结果链表,并将较小结点后移一位。
如果有一个为空,结束遍历,则将未遍历完的链表,直接挂接到结果链表。

时间复杂度: 假设每个链表的最长长度是 n。在第一次合并后,结果链表的长度为 n;第二次合并后,结果链表的长度为 2n,第 i 次合并后,结果链表的长度为 in。第 i 次合并的时间代价是 O(n+(i−1)×n)= O(in),那么总的时间代价为
O ( ∑ i = 1 k ( i × n ) ) = O ( ( 1 + k ) ⋅ k 2 × n ) = O ( k 2 n ) O(\sum_{i = 1}^{k} (i \times n)) = O(\frac{(1 + k)\cdot k}{2} \times n) = O(k^2 n) O(i=1k(i×n))=O(2(1+k)k×n)=O(k2n)
故渐进时间复杂度为 O ( k 2 n ) O(k^2n) O(k2n),其中 k 为链表个数。

空间复杂度: 没有用到与 k 和 n 规模相关的辅助空间,故渐进空间复杂度为 O(1)。

下面以 Golang 为例给出实现。

func merge(head1, head2 *ListNode) *ListNode {dummyHead := &ListNode{}temp, temp1, temp2 := dummyHead, head1, head2for temp1 != nil && temp2 != nil {if temp1.Val < temp2.Val {temp.Next = temp1temp1 = temp1.Next} else {temp.Next = temp2temp2 = temp2.Next}temp = temp.Next}if temp1 != nil {temp.Next = temp1} else {temp.Next = temp2}return dummyHead.Next
}func mergeKLists(lists []*ListNode) *ListNode {var head *ListNodefor _, l := range lists {head = merge(head, l)}return head
}

方法二:分治合并

可以优化方法一,采用分治的方法进行合并。

  • 将 k 个链表配对并将同一对中的链表合并;
  • 第一轮合并以后, k 个链表被合并成了 k 2 \frac{k}{2} 2k个链表,然后是 k 4 \frac{k}{4} 4k 个链表, k 8 \frac{k}{8} 8k 个链表等等。
    重复这一过程,直到我们得到了最终的有序链表。
  • 重复这一过程,直到我们得到最终的有序链表。

在这里插入图片描述
时间复杂度: 考虑递归「向上回升」的过程,每一轮合并的时间复杂度都是 O(kn),需要合并 logk 轮,所以总的时间复杂度是 O(kn*logk)。

空间复杂度: 递归会使用到 O(log⁡k) 空间代价的栈空间。

下面以 Golang 为例给出实现。

func merge(head1, head2 *ListNode) *ListNode {dummyHead := &ListNode{}temp, temp1, temp2 := dummyHead, head1, head2for temp1 != nil && temp2 != nil {if temp1.Val < temp2.Val {temp.Next = temp1temp1 = temp1.Next} else {temp.Next = temp2temp2 = temp2.Next}temp = temp.Next}if temp1 != nil {temp.Next = temp1} else {temp.Next = temp2}return dummyHead.Next
}func divideMerge(lists []*ListNode, l, r int) *ListNode {if l == r {return lists[l]}mid := (l + r) / 2// 合并左链表lhead := divideMerge(lists, l, mid)// 合并右链表rhead := divideMerge(lists, mid+1, r)// 合并左右链表return merge(lhead, rhead)
}func mergeKLists(lists []*ListNode) *ListNode {if len(lists) == 0 {return nil}if len(lists) == 1 {return lists[0]}return divideMerge(lists, 0, len(lists)-1)
}

方法三:使用优先队列合并

这个方法和前两种方法的思路有所不同,我们需要维护当前每个链表没有被合并的元素的最前面一个,kkk 个链表就最多有 kkk 个满足这样条件的元素,每次在这些元素里面选取 val\textit{val}val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。

时间复杂度: 考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(log⁡k),这里最多有 kn 个结点,对于每个结点都被插入删除各一次,故总的时间代价为 O(kn*log⁡k)。

**空间复杂度:**这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。

下面以 C++ 为例给出实现。

class Solution {
public:struct Status {int val;ListNode *ptr;bool operator < (const Status &rhs) const {return val > rhs.val;}};priority_queue <Status> q;ListNode* mergeKLists(vector<ListNode*>& lists) {for (auto node: lists) {if (node) q.push({node->val, node});}ListNode head, *tail = &head;while (!q.empty()) {auto f = q.top(); q.pop();tail->next = f.ptr; tail = tail->next;if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});}return head.next;}
};

参考文献

23. 合并K 个升序链表 - LeetCode

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

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

相关文章

华为OD机试 - 运输时间(Java JS Python C)

题目描述 M(1 ≤ M ≤ 20)辆车需要在一条不能超车的单行道到达终点,起点到终点的距离为 N(1 ≤ N ≤ 400)。 速度快的车追上前车后,只能以前车的速度继续行驶,求最后一辆车到达目的地花费的时间。 注:每辆车固定间隔 1 小时出发,比如第一辆车 0 时出发,第二辆车 1 …

Python——基本语法(二)

一、while 循环 语法&#xff1a; while 条件表达式:条件表达示为真&#xff0c;就执⾏这⾥的代码&#xff0c;必须缩进 4 个空格多⾏代码保持缩进⼀致 条件表达式可以是: True # 布尔值的 True 1 < 10 # 凡是在 if 语句中使⽤的判断表达示&#xff0c;这⾥都可以使…

【Java实战项目】基于ssm的流浪动物领养系统网站

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【音视频原理】图像相关概念 ② ( 帧率 | 常见帧率标准 | 码率 | 码率单位 )

文章目录 一、帧率1、帧率简介2、常见帧率标准3、帧率 刷新率 二、码率1、码率简介2、码率单位 一、帧率 1、帧率简介 帧率 Frame Rate , 帧 指的是 是 画面帧 , 帧率 是 画面帧 的 速率 ; 帧率 的 单位是 FPS , Frames Per Second , 是 每秒钟 的 画面帧 个数 ; 帧率 是 动画…

VR远程的实现

VR远程是一种使用虚拟现实&#xff08;VR&#xff09;技术进行远程操作的方法。通过VR设备&#xff0c;用户可以在虚拟环境中进行操作&#xff0c;并远程控制物理设备或机器人。 VR远程的实现通常需要以下几个步骤&#xff1a; 建立虚拟环境&#xff1a;使用VR技术创建一个与…

springboot 2.6.13 jdk 1.8版本 常用pom包 application.yml文件记录

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.13</version><relativePath/> <!-- lookup parent from repository --></parent> 数据…

漫漫数学之旅006

文章目录 经典格言数学习题古今评注名人小传 - 格洛里亚斯泰纳姆经典格言 数学上有才华的人没有在历史或英语上有才华的人那么多。——格洛里亚斯泰纳姆(Gloria Steinem) 数学习题 求阴影部分的面积。 古今评注 查尔斯巴贝奇,这位19世纪的英国数学家、发明家和机械工程…

相机内外参标定综合

相机内外参标定 内外参标定常用的工具相机成像原理内外参标定数学原理1&#xff09;求解内参矩阵与外参矩阵的积2&#xff09;求解内参矩阵3&#xff09;求解外参矩阵 内外参标定常用的工具 如图所示&#xff0c;棋盘格是很常见使用的标定工具 左下角写着棋盘格的参数&#xf…

Qt绘画的使用

1. 绘图 绘图组件&#xff1a; 1、绘画对象 2、绘画位置 3、绘画工具 4、绘画时机 绘画时机&#xff1a; 当整个窗口或窗口的一部分需要重新绘制时&#xff0c;会调用绘制事件处理函数 void QWidget::paintEvent(QPaintEvent *event) 绘画对象&#xff1a; QPainter类&#xff…

❤ vue的实际使用

❤ vue的实际使用 vue项目中video标签的动态路径使用方法及里面的坑 需求&#xff1a; 在详情展示的时候播放.mp4文件,然后动态改变这个视频的路径无法生效 原因&#xff1a; 使用video标签的时候,会在里面嵌套一个source标签 <video controls"controls" wi…

群晖Drive搭建云同步服务器结合内网穿透实现Obsidian笔记文件远程多端同步

文章目录 一、简介软件特色演示&#xff1a; 二、使用免费群晖虚拟机搭建群晖Synology Drive服务&#xff0c;实现局域网同步1 安装并设置Synology Drive套件2 局域网内同步文件测试 三、内网穿透群晖Synology Drive&#xff0c;实现异地多端同步Windows 安装 Cpolar步骤&#…

使用内网穿透解决电信无公网IP难题,神卓互联

事情经过 事情是这样的&#xff0c;由于客户的单位通了电信宽带&#xff0c;然后采购了我们的ERP系统安装在单位的服务器上&#xff0c;在单位的时候可以通过输入服务器的局域网Ip地址访问&#xff0c;也就是192.168.2.1xx这样的地址&#xff0c;访问确实没有问题&#xff0c;…

ARCGIS PRO SDK 地图图层单一符号化_____线图层

1、定义渲染器线符号&#xff1a; 1)、自定义线符号 Dim Linesymbol As CIMLineSymbol SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.RedRGB,width ,SimpleLineStyle) width: 要构造的线条符号的宽度。 Simple…

【漏洞复现】Sentinel Dashboard默认弱口令漏洞

Nx01 产品简介 Sentinel Dashboard是一个轻量级的开源控制台&#xff0c;提供机器发现以及健康情况管理、监控、规则管理和推送的功能。它还提供了详细的被保护资源的实际访问统计情况&#xff0c;以及为不同服务配置的限流规则。 Nx02 漏洞描述 Sentinel Dashboard存在默认弱…

低代码配置-列表页组件设计

保存 表单属性存放 — bill筛选项配置存放 — filterLayout列表按钮存放 — buttonLayout列表布局存放 — listLayoutapi存放 — api 数据结构 layout:{// 存放表单基础配置bill:{},// 存放按钮基础配置buttonLayout:{// inSide 行内按钮 // outSide 全局按钮},// 存放表格列…

墙地砖外形检测的技术方案-外部轮廓检测算法

Ramer算法 利用Canny算子得到墙地砖轮廓后&#xff0c;必须进一步将轮廓线精确分段成墙地砖的四条边&#xff0c;从而可得到墙地砖轮廓尺寸、边直度和直角度指标。采用如下算法实现&#xff1a; 第1&#xff0c;选择较高阈值&#xff0c;利用ramer算法将轮廓线用多边形&#…

软件测试|Python 用户输入和字符串格式化

简介 在 Python 中&#xff0c;用户输入和字符串格式化是编程中常见的任务之一。用户输入使我们能够与用户交互&#xff0c;而字符串格式化帮助我们创建美观的输出。本文将介绍如何在 Python 中执行这些任务&#xff0c;并提供详细示例。 用户输入 在 Python 中&#xff0c;…

MySQL报错:this is incompatible with sql_mode=only_full_group_by

mysql 5.7报错 which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_modeonly_full_group_by解决办法 修改配置文件 my.cnf [mysqld] sql_modeSTRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZE…

[论文阅读]DeepFusion

DeepFusion Lidar-Camera Deep Fusion for Multi-Modal 3D Object Detection 用于多模态 3D 物体检测的激光雷达相机深度融合 论文网址&#xff1a;DeepFusion 论文代码&#xff1a;DeepFusion 摘要 激光雷达和摄像头是关键传感器&#xff0c;可为自动驾驶中的 3D 检测提供补…

多输入多输出 | Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出预测

多输入多输出 | Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出预测预测效果基本介绍模型背景程序设计参考资料 预测效果 基本介绍 Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出…