牛客热题:合并K个升序链表

2024-05-01 05:04

本文主要是介绍牛客热题:合并K个升序链表,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

📟作者主页:慢热的陕西人

🌴专栏链接:力扣刷题日记

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

在这里插入图片描述

文章目录

  • 牛客热题:合并K个升序链表
    • 题目链接:
    • 方法一:复用2个升序链表的方法
      • 思路:
      • 代码:
      • 复杂度:
    • 方法二:第一种方法的分治优化-->借鉴牛客题解
      • 思路:
      • 代码:
      • 复杂度:
    • 方法三:优先队列-->借鉴牛客题解
      • 思路:
      • 代码:
      • 复杂度:

牛客热题:合并K个升序链表

题目链接:

合并k个已排序的链表_牛客题霸_牛客网 (nowcoder.com)

方法一:复用2个升序链表的方法

思路:

  • 首先我们知道如何合并两个升序链表
  • 那么我们先将k个的前两个合并,然后再将和这个合并的链表和下一个链表合并…直到所有的链表都被合并

代码:

 ListNode* Merge(ListNode* pHead1, ListNode* pHead2){//申请一个哨兵位ListNode* head = new ListNode(0);ListNode* cur = head;while(pHead1 != nullptr && pHead2 != nullptr){if(pHead1->val <= pHead2->val){cur->next = pHead1;cur = cur->next;pHead1 = pHead1->next;}else{cur->next = pHead2;cur = cur->next;pHead2 = pHead2->next;}}//p1未完的情况while(pHead1 != nullptr){cur->next = pHead1;cur = cur->next;pHead1 = pHead1->next;}//p2未完的情况while(pHead2 != nullptr){cur->next = pHead2;cur = cur->next;pHead2 = pHead2->next;}return head->next;}ListNode* mergeKLists(vector<ListNode*>& lists) {if(lists.size() == 0) return nullptr;ListNode* ret = lists[0];for(int i = 1; i < lists.size(); ++i){ret = Merge(ret, lists[i]);}  return ret;}

复杂度:

时间复杂度:O( N 2 N^2 N2), 但其实一般达不到O( N 2 N^2 N2);

  • 对于第一个链表:我们遍历了k-1次
  • 对于第二个链表:我们遍历了k-2次
  • 对于最后一个链表:我们遍历了1次

由于所有的链表的长度加起来为 n n n,那么平均长度为 n / k n / k n/k,

每个链表最多被遍历k - 1次,我们放缩为k次,那么需要最多 n ∗ n n*n nn次运算.

空间复杂度:O(1), 使用了常数个额外的空间。

方法二:第一种方法的分治优化–>借鉴牛客题解

思路:

具体做法:

  • step 1:从链表数组的首和尾开始,每次划分从中间开始划分,划分成两半,得到左边 n / 2 n/2 n/2个链表和右边 n / 2 n/2 n/2个链表。
  • step 2:继续不断递归划分,直到每部分链表数为1.
  • step 3:将划分好的相邻两部分链表,按照两个有序链表合并的方式合并,合并好的两部分继续往上合并,直到最终合并成一个链表。

合并k个升序链表

代码:

     ListNode* Merge(ListNode* pHead1, ListNode* pHead2){//申请一个哨兵位ListNode* head = new ListNode(0);ListNode* cur = head;while(pHead1 != nullptr && pHead2 != nullptr){if(pHead1->val <= pHead2->val){cur->next = pHead1;cur = cur->next;pHead1 = pHead1->next;}else{cur->next = pHead2;cur = cur->next;pHead2 = pHead2->next;}}//p1未完的情况while(pHead1 != nullptr){cur->next = pHead1;cur = cur->next;pHead1 = pHead1->next;}//p2未完的情况while(pHead2 != nullptr){cur->next = pHead2;cur = cur->next;pHead2 = pHead2->next;}return head->next;}ListNode* DivideMerge(vector<ListNode*> & lists, int l, int r){//不存在区间if(l > r) return nullptr;//已到达最小的区间if(l == r) return lists[l];int mid = l + r >> 1;return Merge(DivideMerge(lists, l, mid), DivideMerge(lists, mid + 1, r));}ListNode* mergeKLists(vector<ListNode*>& lists) {return DivideMerge(lists, 0, lists.size() - 1);}

复杂度:

  • 时间复杂度: O ( n l o g 2 K ) O(nlog_2K) O(nlog2K),其中 n n n为所有链表的总节点数,分治为二叉树型递归,最坏情况下二叉树每层合并都是O(N)个节点,因为分治一共有 O ( l o g 2 K ) O(log_2K) O(log2K)
  • 空间复杂度: O ( l o g 2 K ) O(log_2K) O(log2K),最坏的情况需要向下递归 l o g 2 K log_2K log2K层,需要 l o g 2 K log_2K log2K个函数栈帧

方法三:优先队列–>借鉴牛客题解

思路:

如果非要按照归并排序的合并思路,双指针不够用,我们可以直接准备k个指针,每次比较得出k个数字中的最小值,我们可以借助堆,也就是优先队列—>priority_queue来完成这一点。

代码:

   struct cmp{bool operator()(ListNode* a, ListNode* b){return a->val > b->val;}};ListNode* mergeKLists(vector<ListNode*>& lists) {//小根堆priority_queue<ListNode*, vector<ListNode*>, cmp> pq;//遍历所有链表的第一个元素,并且把不为空的加入到优先队列for(int i = 0; i < lists.size(); ++i){if(lists[i] != nullptr) pq.push(lists[i]);}ListNode* res = new ListNode(-1);ListNode* cur = res;while(!pq.empty()){//取出最小的元素ListNode* t = pq.top();pq.pop();//链接到尾部cur->next = t;cur = cur->next;//将该链表的下一个指针加入到优先队列if(t->next != nullptr)pq.push(t->next);}return res->next;}

复杂度:

  • 时间复杂度: O ( n l o g 2 K ) O(nlog_2K) O(nlog2K),其中 n n n为所有链表的总节点数,每次加入优先队列的复杂度为 O ( l o g 2 K ) O(log_2K) O(log2K)
  • 空间复杂度: O ( K ) O(K) O(K),优先队列的大小为K

这篇关于牛客热题:合并K个升序链表的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/950775

相关文章

基于C#实现PDF文件合并工具

《基于C#实现PDF文件合并工具》这篇文章主要为大家详细介绍了如何基于C#实现一个简单的PDF文件合并工具,文中的示例代码简洁易懂,有需要的小伙伴可以跟随小编一起学习一下... 界面主要用于发票PDF文件的合并。经常出差要报销的很有用。代码using System;using System.Col

Python视频剪辑合并操作的实现示例

《Python视频剪辑合并操作的实现示例》很多人在创作视频时都需要进行剪辑,本文主要介绍了Python视频剪辑合并操作的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录介绍安装FFmpegWindowsMACOS安装MoviePy剪切视频合并视频转换视频结论介绍

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

csu1329(双向链表)

题意:给n个盒子,编号为1到n,四个操作:1、将x盒子移到y的左边;2、将x盒子移到y的右边;3、交换x和y盒子的位置;4、将所有的盒子反过来放。 思路分析:用双向链表解决。每个操作的时间复杂度为O(1),用数组来模拟链表,下面的代码是参考刘老师的标程写的。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-

建立升序链表

题目1181:遍历链表 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2744 解决:1186 题目描述: 建立一个升序链表并遍历输出。 输入: 输入的每个案例中第一行包括1个整数:n(1<=n<=1000),接下来的一行包括n个整数。 输出: 可能有多组测试数据,对于每组数据, 将n个整数建立升序链表,之后遍历链表并输出。 样例输

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点