力扣hot100:23. 合并 K 个升序链表

23. 合并 K 个升序链表
在这里插入图片描述
这题非常容易想到归并排序的思路,俩升序序列合并,可以使用归并的方法。

不过这里显然是一个多路归并排序;包含多个子数组的归并算法,这可以让我们拓展归并算法的思路。

假设n是序列个数,ni是单个序列长度,length是单个序列最大长度

1、顺序单次归并

从左往右依次进行归并,但是这种方法存在一定的缺点。假设n是序列个数,ni是单个序列长度,根据题设,这个方法的最大比较次数至少是:
n 1 + ( n 1 + n 2 ) + ( n 1 + n 2 + n 3 ) ⋅ ⋅ ⋅ = n ∗ n 1 + ( n − 1 ) ∗ n 2 + ( n − 2 ) ∗ n 3 ⋅ ⋅ ⋅ < = n ∗ ( n 1 + n 2 + n 3 + ⋅ ⋅ ⋅ ) = n 2 ∗ l e n g t h < = 1 0 4 ∗ 500 ∗ 1 0 4 n1+(n1+n2)+(n1+n2+n3)··· = n*n1 + (n-1)*n2 + (n-2)*n3··· <= n*(n1+n2+n3+···) = n^2 * length <=10^4*500*10^4 n1+(n1+n2)+(n1+n2+n3)⋅⋅⋅=nn1+(n1)n2+(n2)n3⋅⋅⋅<=n(n1+n2+n3+⋅⋅⋅)=n2length<=104500104
这相当于每个序列都需要被比较序列个数次,这换成是多路归并的数组合并也是一样的。

官方:
在这里插入图片描述
在这里插入图片描述

class Solution {
public:ListNode* mergeKLists(vector<ListNode*>& lists) {ListNode * head = nullptr;for(int i = lists.size() - 1;i >= 0; --i){head = merge(head, lists[i]);ListNode * temp = head;}return head;}
private:ListNode * merge(ListNode * p,ListNode * q){if(!p) return q;if(!q) return p;ListNode * head = p;if(head->val > q->val) head = q;if(head == p) p = p->next;else q = q->next;ListNode * temp = head;while(p && q){if(p->val > q->val){head->next = q;q = q->next;}else{head->next = p;p = p->next;}head = head->next;}head->next = p ? p : q;return temp;}
};

2、分治归并

使用分治的思想排序是很容易想到的,但是不能很容易的知道分治归并速度一定更快,接下来让我详细思考一下是否会更快:
我们可以考虑,每次将序列数量减半合并,那么每一层合并使用的时间是 O ( l e n g t h ∗ n ) O(length*n) O(lengthn),我们知道每层数量减半,那么一共是有 O ( l o g n ) O(logn) O(logn)层,所以时间复杂度为 O ( n l o g n ∗ l e n g t h ) O(nlogn * length) O(nlognlength)

为什么分治归并会比普通顺次归并要快?
可以这样看一下,使用分治,将所有数分为两个区间[l,mid][mid+1,r],左区间的数 和 右区间的数只会在最后合并时比较一次,其他时候打死不相往来。而使用顺序归并,左区间的数 和 右区间的数会比较很多次,在考虑到
在这里插入图片描述
在这里插入图片描述

class Solution {
public:ListNode* mergeKLists(vector<ListNode*>& lists) {if(lists.size() == 0) return nullptr;return mergesort(lists, 0, lists.size() - 1);}
private:ListNode * merge(ListNode * p,ListNode * q){if(!p) return q;if(!q) return p;ListNode * head = p;if(head->val > q->val) head = q;if(head == p) p = p->next;else q = q->next;ListNode * temp = head;while(p && q){if(p->val > q->val){head->next = q;q = q->next;}else{head->next = p;p = p->next;}head = head->next;}head->next = p ? p : q;return temp;}ListNode * mergesort(vector<ListNode*>& lists,int left,int right){if(left == right) return lists[left];int mid = (left + right) >> 1;ListNode * p = mergesort(lists,left,mid);ListNode * q = mergesort(lists,mid + 1, right);return merge(p, q);}
};

3、使用优先队列合并

这种方式非常牛。

我们将所有序列,依据序列头部的元素大小放入一个优先队列,那么这个优先队列的深度是 l o g n logn logn,然而我们每次取出一个结点它的头部必然是现在里面最小的,将它放入待合并的目标序列中,然后将该序列后移一位,插入到优先队列中。因此每个元素插入时间是 O ( l o g n ) O(logn) O(logn),一共有 ( l e n g t h ∗ n ) (length * n) (lengthn)个元素。所以总时间为 O ( n l o g n ∗ l e n g t h ) O(nlogn*length) O(nlognlength)
在这里插入图片描述

class Solution {
public:ListNode* mergeKLists(vector<ListNode*>& lists) {if(lists.size() == 0) return nullptr;priority_queue<ListNode *,vector<ListNode *>,Sort> q;for(int i = lists.size() - 1;i >= 0; --i) if(lists[i]) q.push(lists[i]);ListNode * dummy = new ListNode;ListNode * temp = dummy;while(!q.empty()){ListNode * head = q.top();q.pop();temp->next = head;temp = temp->next;head = head->next;if(head) q.push(head);}temp = dummy->next;delete dummy;return temp;}
private:struct Sort{bool operator ()(const ListNode * a,const ListNode * b){return a->val > b->val;}};
};

能够实现优先队列,那么这个问题就很容易被解决。

  • 我们需要注意两个问题
    • 优先队列使用的比较函数必须自定义为结构体或者符号重载
    • 优先队列使用的比较函数的大于号小于号取值,和sort刚好相反。

使用方式:

priority_queue<Exp,vector<Exp>,cmp> q;
struct cmp{bool operator() (Exp a, Exp b){if() return true;return false;}
}

唯一变化的就是括号里面的类型Exp和你想要定义的比较方式。

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

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

相关文章

大规模服务治理中etcd的实践与深度应用

导读&#xff1a;随着企业对于服务治理的日益重视&#xff0c;特别是在云原生和微服务架构的广泛应用下&#xff0c;百度小程序团队基于大模型服务治理的实战经验&#xff0c;结合分布式开源KV产品etcd&#xff0c;分享了其核心技术Raft与boltdb的实现原理&#xff0c;并深入剖…

Simulink从0搭建模型07-P8for循环的使用

Simulink从0搭建模型07-P8for循环的使用 今日学习内容1. For Iterator Subsystem模块介绍1.1. 累加器1.2. For Iterator1.3.小结 2. states介绍3. Set next i&#xff08;相当break)学习心得 今日学习内容 b站视频 【Simulink 0基础入门教程 P8 for循环的使用 For Itrator Sub…

基于 Coze 从 0-1 搭建专属 小白的Bot 机器人

基于 Coze 从 0-1 搭建专属 小白的Bot 机器人 ​ 作为一个GIS从业人员&#xff0c;对于AI的使用是必不可少的&#xff0c;在过去的一两年里各种大模型频出&#xff0c;AI技术已经成为GIS领域的一项重要工具&#xff0c;为我们提供了许多强大的功能和解决方案。看到好文章都在介…

【Android】【netd】网络相关调试技巧

网络调试技巧总结 ifconfig ifconfig 查看网卡信息 ifconfig -S tcpdump tcpdump -i any -n icmp 查看流量出入ip addr 上面的log 以及ifcong -S 信息可以知道&#xff0c;当前是从wlan0 网卡请求数据。 iptable iptable 部分指令 //禁止www.baidu.com 网址流量进入&a…

2024广东省赛 G.Menji 和 gcd

题目 #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #define lson p << 1 #define rson p << 1 | 1 #define ll long long const int maxn 1e6 5, inf 1e12, maxm 4e4 …

【测评】雨云香港三区云服务器,2核2G 5兆,仅需38元/月

写在前面 雨云香港三区云服务器&#xff0c;高性能的 AMD EPYC 处理器 企业级 NVME SSD 高性能云服务器。2核2G 10兆 400G防御&#xff0c;仅需38元/月&#xff0c;年付7折仅 319.2元/年。 官网&#xff1a;https://www.rainyun.com 本次测评服务器配置如下&#xff1a; C…

【JavaScript】P1 JavaScript 是什么、其组成

1.1 JavaScript 是什么 JavaScript 是一种运行在浏览器的编程语言&#xff0c;用于实现人机交互效果。其作用包含&#xff1a; 监听用户行为并指导网页做出反馈。针对表单数据进行合法性验证。获取后台数据&#xff0c;渲染到前端界面。服务器编程&#xff0c;最后端的事情&a…

什么是老板和工程师都喜欢的FMEA?——FMEA软件

免费试用FMEA软件-免费版-SunFMEA 在企业管理与工程技术领域&#xff0c;FMEA&#xff08;潜在失效模式与效应分析&#xff09;早已不仅仅是一个概念或工具&#xff0c;它更是一种思维方式和团队协作的精髓。那么&#xff0c;究竟什么才是老板和工程师都喜欢的FMEA呢&#xff…

安卓ADB通过WIFI无线连接手机[通过无线安装APK]

安卓ADB通过无线连接手机 本文摘录于&#xff1a;https://www.cnblogs.com/zhuxibo/p/14261117.html只是做学习备份之用&#xff0c;绝无抄袭之意&#xff0c;有疑惑请联系本人&#xff01; 别人给的操作确实可行,我这里实操记录如下: AdministratorpiaoranPC MINGW64 /e/Wor…

基于h5和大数据的游戏数据型网站-计算机毕业设计源码30844

摘 要 在目前的形势下&#xff0c;科技力量已成为我国的主要竞争力。而在科学技术领域&#xff0c;计算机的使用逐渐达到成熟&#xff0c;无论是从国家到企业再到家庭&#xff0c;计算机都发挥着其不可替代的作用&#xff0c;可以说计算机的可用领域遍及生活、工作的各个方面。…

找到可靠的APP外包开发公司

找到可靠的APP外包开发公司需要经过一系列细致的筛选和评估。以下是寻找和选择一家合适的APP外包开发公司的步骤和注意事项。选择一家可靠的APP外包开发公司需要经过详细的研究和多方面的评估&#xff0c;确保公司能够满足项目需求并提供高质量的服务。北京木奇移动技术有限公司…

【乐吾乐3D可视化组态编辑器】灯光

灯光 在场景属性中&#xff0c;我们介绍了HDR&#xff0c;它的作用是为场景提供环境光&#xff0c;如果网格设置了PBR材质&#xff0c;那么网格表面就会反射出光照效果。这是为场景提供环境光的手段之一&#xff0c;但是它也有缺陷&#xff0c;一是只对PBR材质有效&#xff0c…

实用新型专利申请被驳回原因

实用新型专利作为知识产权的重要组成部分&#xff0c;对推动技术创新和产业发展具有重要意义。然而&#xff0c;在申请实用新型专利的过程中&#xff0c;有时会遇到被驳回的情况。 实用新型专利被驳回的一个常见原因是技术方案不具备新颖性、创造性和实用性等专利授权条件。专利…

LLama学习记录

学习前&#xff1a; 五大问题&#xff1a; 为什么SwiGLU激活函数能够提升模型性能&#xff1f;RoPE位置编码是什么&#xff1f;怎么用的&#xff1f;还有哪些位置编码方式&#xff1f;GQA&#xff08;Grouped-Query Attention, GQA&#xff09;分组查询注意力机制是什么&…

ATA-2021B高压放大器在锂电池超声检测中的应用

锂电池一种高能量密度的电池&#xff0c;已经广泛应用于可穿戴设备、移动电话、笔记本电脑和电动汽车等领域中。然而&#xff0c;其在使用过程中存在着一定的安全隐患&#xff0c;锂电池内部的化学反应和充放电过程可能会导致电池发热&#xff0c;甚至发生燃烧。Aigtek安泰电子…

JS中运算符详解

一&#xff1a;赋值运算符 1 类型 、、-、*、/等 2 如何运行 &#xff0c;是将等号右边的数赋值给左边以为例&#xff0c;let num 5&#xff1b;num2等价于numnum2 二&#xff1a;一元运算符 1 自增运算符 什么是一元运算符 只需要一个操作数就可以运算的运算符 &#x…

LeetCode 377.组合总和Ⅳ

这题是我蠢了&#xff0c;它说是组合数我就信了&#xff0c;言尽于此 class Solution { public:int combinationSum4(vector<int>& nums, int target) {vector<int> dp(2000,0);dp[0]1;for(int i0;i<target;i){for(int j0;j<nums.size();j){if(i>nums…

MySQL--二进制日志

目录 一、作用 二、binlog配置 1.查看当前配置 2.修改配置文件​ 3.binlog配置参数解释 三、binlog记录内容说明 1.记录内容 2.DDL、DCL记录格式 3.DML记录格式 4.记录内容查看 四、bin_log_format 记录模式 1.行模式 Row 2.语句模式 Statement 3.混合模式 五、…

单线程 vs 多进程:Python网络爬虫效率对比

概述 在网络爬虫的开发过程中&#xff0c;性能优化是一个重要的考虑因素。本文将概述单线程和多进程在Python网络爬虫中的应用&#xff0c;并对比它们的效率。 单线程爬虫是最基本的爬虫模型&#xff0c;它按顺序一个接一个地处理任务。这种方法的优点是实现简单&#xff0c;易…

探索数据结构:顺序表的实现与应用

&#x1f511;&#x1f511;博客主页&#xff1a;阿客不是客 &#x1f353;&#x1f353;系列专栏&#xff1a;渐入佳境之数据结构与算法 欢迎来到泊舟小课堂 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ​ 一、什么是顺序表 顺序表是用一段物理地址连续…