【LeetCode】23. 合并 K 个升序链表

news2024/11/25 12:51:49

23. 合并 K 个升序链表(困难)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法一:顺序合并

思路

在这里插入图片描述
在这里插入图片描述

ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
    if ((!a) || (!b)) return a ? a : b;
    ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
    while (aPtr && bPtr) {
        if (aPtr->val < bPtr->val) {
            tail->next = aPtr; aPtr = aPtr->next;
        } else {
            tail->next = bPtr; bPtr = bPtr->next;
        }
        tail = tail->next;
    }
    tail->next = (aPtr ? aPtr : bPtr);
    return head.next;
}

在这里插入图片描述

代码

/**
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* merge2Lists(ListNode* a, ListNode* b){
        // 如果二者中有空链表 返回非空链表
        if((!a) || (!b))    return a ? a : b;
        ListNode head, *tail = &head, *aptr=a, *bptr=b;
        while(aptr && bptr){
            // a的值比较小 加入a
            if(aptr->val < bptr->val){
                tail->next = aptr;
                aptr = aptr-> next;
            }
            // b的值比较小
            else{
                tail->next = bptr;
                bptr = bptr->next;
            }
            tail = tail -> next;
        }
        tail->next = (aptr ? aptr : bptr);
        // 因为head是节点 所以用.访问
        return head.next;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) { 
        ListNode *ans=nullptr;
        for(int i=0; i<lists.size(); ++i){
            // 将ans和list[i]逐一合并
            ans = merge2Lists(ans, lists[i]);
        }
        return ans;
    }
};

方法二:分治

思路

在这里插入图片描述
在这里插入图片描述

代码

/**
 * 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) {}
 * };
 */
class Solution {
public:
    ListNode* merge2Lists(ListNode* a, ListNode* b){
        // 如果二者中有空链表 返回非空链表
        if((!a) || (!b))    return a ? a : b;
        ListNode head, *tail = &head, *aptr=a, *bptr=b;
        while(aptr && bptr){
            // a的值比较小 加入a
            if(aptr->val < bptr->val){
                tail->next = aptr;
                aptr = aptr-> next;
            }
            // b的值比较小
            else{
                tail->next = bptr;
                bptr = bptr->next;
            }
            tail = tail -> next;
        }
        tail->next = (aptr ? aptr : bptr);
        // 因为head是节点 所以用.访问
        return head.next;
    }
    ListNode* merge(vector<ListNode*> a, int l, int r){
        if(l == r) return a[l];
        if(l > r)   return nullptr;
        int mid = (l + r) / 2;
        return merge2Lists(merge(a, l, mid), merge(a, mid+1, r));
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) { 
        return merge(lists, 0, lists.size()-1);
    }
};

方法三:优先队列

  • 什么是优先队列

    优先队列是一种容器适配器,采用了这样的数据结构,保证了第一个元素总是整个优先队列中最大的(或最小的)元素

    优先队列默认使用vector作为底层存储数据的容器,在vector上使用了堆算法将vector中的元素构造成堆的结构,所以其实我们就可以把它当作堆,凡是需要用堆的位置,都可以考虑优先队列。

  • priority_queue类模板参数

    template <class T, class Container = vector<T>,
    class Compare = less<typename Container::value_type> >
    
    class priority_queue;
    
    • class T:T是优先队列中存储的元素的类型

    • class Container = vector< T>:Container是优先队列底层使用的存储结构,可以看出来,默认采用vector。

    • class Compare = less< typename Container::value_type> :Compare是定义优先队列中元素的比较方式的类。默认是按小于(less)的方式比较,创建出来的就是大堆。所以优先队列默认就是大堆。如果需要创建小堆,就需要将less改为greater

      下面是less类的内部函数,less类的内部重载(),参数列表中有左右两个参数,左边小于右边的时候返回true,此时优先队列就是大堆。

      template <class T> 
              struct less : binary_function <T,T,bool> {
                bool operator() (const T& x, const T& y) const {return x<y;}
      };
      

      注意:less类和greater类只能比较内置类型的数据的大小,如果用户需要比较自定义类型的数据,就需要自己定义一个比较类,并且重载()

      同时less类和greater类也具有模板参数,因为他们也是模板,所以我们如果要存储自定义类型的元素,就要将自定义类型作为模板参数传递给less类和greater类

  • 示例

    因为priority_queue是模板,所以创建对象时需要传入模板参数,但是由于模板参数内部是具有默认值的,所以创建大堆时可以只传递元素类型即可。但创建小堆的时候,模板参数是不可以省略的。

    //完整版按大堆创建对象
    priority_queue<int,vector<int>, less<int>> q;
    
    //按小堆创建对象(按小堆创建时参数列表不可以省略)
    priority_queue<int, vector<int>, greater<int>> q;
    

在这里插入图片描述

  • 注意,因为 Comp 函数默认是对最大堆进行比较并维持递增关系,如果我们想要获取到最小的节点值,则需要实现一个最小堆,因此比较函数应该维持递减关系,所以 operator() 中返回时用大于号进行比较。

代码

/**
 * 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) {}
 * };
 */
class Solution {
public:
// 比较模板
struct Comp{
    bool operator() (ListNode* l1, ListNode* l2){
        // 最小堆 
        return l1->val > l2->val;
    }   
};
    ListNode* mergeKLists(vector<ListNode*>& lists) { 
        if(lists.empty()) return nullptr;

        // 最小堆的优先队列,所以模板不可以省略
        priority_queue<ListNode*, vector<ListNode*>, Comp> q;

        // 只存入每个链表的第一个元素
        for(ListNode* list:lists){
            // 注意要非空
            if(list)
                q.push(list);
        }

        // dummy 虚拟节点,最终返回它的下一个位置
        ListNode *dummy = new ListNode(0), *cur = dummy;
        while(!q.empty()){
            cur->next = q.top();
            q.pop();
            cur = cur -> next;
            // 即q.top()所在链表还没有遍历结束
            // 那么需要存入它的下一个节点
            if(cur->next){
                q.push(cur->next);
            }
        }
        return dummy->next;
    }
};

参考资料

  1. 官方题解
  2. C++ 优先队列 priority_queue 使用篇

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

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

相关文章

【第十期】Apache DolphinScheduler 每周 FAQ 集锦

点击蓝字 关注我们 摘要 为了让 Apache DolphinScheduler 的广大用户和爱好者对于此项目的疑问得到及时快速的解答&#xff0c;社区特发起此次【每周 FAQ】栏目&#xff0c;希望可以解决大家的实际问题。 关于本栏目的要点&#xff1a; 本栏目每周将通过腾讯文档&#xff08;每…

卡尔曼滤波与组合导航原理(十二)扩展卡尔曼滤波:EKF、二阶EKF、迭代EKF

文章目录 一、多元向量的泰勒级数展开二、扩展Kalman滤波三、二阶滤波四、迭代EKF滤波 一、多元向量的泰勒级数展开 { y 1 f 1 ( X ) f 1 ( x 1 , x 2 , ⋯ x n ) y 2 f 2 ( X ) f 2 ( x 1 , x 2 , ⋯ x n ) ⋮ y m f m ( X ) f m ( x 1 , x 2 , ⋯ x n ) \left\{\begin{…

大家都说Java有三种创建线程的方式,并发编程中的惊天骗局

在Java中&#xff0c;创建线程是一项非常重要的任务。线程是一种轻量级的子进程&#xff0c;可以并行执行&#xff0c;使得程序的执行效率得到提高。Java提供了多种方式来创建线程&#xff0c;但许多人都认为Java有三种创建线程的方式&#xff0c;它们分别是继承Thread类、实现…

论文浅尝 | Dually Distilling KGE for Faster and Cheaper Reasoning

笔记整理&#xff1a;张津瑞&#xff0c;天津大学硕士&#xff0c;研究方向为知识图谱 链接&#xff1a;https://dl.acm.org/doi/10.1145/3488560.3498437 动机 知识图谱已被证明可用于各种 AI 任务&#xff0c;如语义搜索&#xff0c;信息提取和问答等。然而众所周知&#xff…

【C++】C++11常用新特性

✍作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;C 目录 一、统一的列表初始化二、 简化声明2.1 auto2.2 decltype2.3 nullptr 三、右值引用和移动语义 -- 重要3.1 区分左值引用和右值引用3.2 对比左值引用看看右值引用使用价值3.3 万能引用和完美转发&#xff08;st…

基于word文档,使用Python输出关键词和词频,并将关键词的词性也标注出来

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 移船相近邀相见&#xff0c;添酒回灯重开宴。 大家好&#xff0c;我是Python进阶者。 一、前言 前几天在有个粉丝问了个问题&#xff0c;大概意思是这样…

一道北大强基题背后的故事(三)——什么样的题是好题?

早点关注我&#xff0c;精彩不错过&#xff01; 上回我们针对这道北大强基题[((1 sqrt(5)) / 2) ^ 12]在答案的基础上给出了出题的可能思路&#xff0c;想一探究竟&#xff0c;相关内容请戳&#xff1a; 一道北大强基题背后的故事&#xff08;二&#xff09;——出题者怎么想的…

【Kubernetes入门】Service四层代理入门实战详解

文章目录 一、Service四层代理概念、原理1、Service四层代理概念2、Service工作原理3、Service原理解读4、Service四种类型 二、Service四层代理三种类型案例1、创建ClusterIP类型Service2、创建NodePort类型Service3、创建ExternalName类型Service 三、拓展1、Service域名解析…

Latex中图片排版(多个子图、横排、竖排、添加小标题)

1、两个子图横排 \begin{figure}[!t] \centering %\includegraphics[width3in]{fig5} \subfloat[subfig figure title]{\includegraphics[scale0.5]{superd2}} \subfloat[subfig figure title]{\includegraphics[scale0.5]{superd2}} \caption{title} \label{fig_6} \end{figu…

阿里发布的百亿级高并发系统(全彩版小册),涵盖了所有的高并发操作

高并发 提到“高并发”相信你们应该都不会感到陌生&#xff01;此时你脑中应该会浮现好多有关高并发的&#xff1a;业务急剧增长、电商购物、电商秒杀、12306抢票、淘宝天猫各种活动等&#xff1b;都是需要用到高并发的&#xff0c;那么如何去设计一个高并发系统抵挡这些冲击呢…

Django的app里面的视图函数

我之前说过需要重点去了解view和model&#xff0c;下面是我的总结。 视图函数是存在view.py里面的&#xff0c;视图函数的主要功能是接收请求、返回响应。在建立应用程序后&#xff0c;先在URL配置文件中加一条配置项指明URL与视图函数的对应关系。然后按照实际需求在视图函数…

三次握手四次挥手过程剖析

【一】预备知识&#xff1a; 1.三次握手并不一定非得成功&#xff0c;最担心得其实就是最后一个akc&#xff08;应答&#xff09;丢失&#xff0c;但是还是有配套得解决方案&#xff0c;比如超时重传机制。 2.连接是需要被保存下来得&#xff0c;是需要被os管理起来得&#xf…

被一个gpio口搞死的一天

今天是新项目调试的第一天。 我起的很早&#xff0c;起早的原因很简单&#xff0c;我家楠哥要我送他上学&#xff0c;他说爸爸没有起到一个当爸爸的责任&#xff0c;他也想让爸爸送他上学&#xff0c;然后我就送了。 7点30起来&#xff0c;8点出发&#xff0c;然后回来看了一下…

IDEA把css/js压缩成一行min文件,idea实现右键压缩css和js文件

前言 发布时有些css和js文件较长多行&#xff0c;导致加载的时候略慢&#xff0c;所以想把指定的css或js压缩 实现 整合 yuicompressor-2.4.8.jar 下载地址1&#xff1a;https://github.com/yui/yuicompressor/releases 下载地址2&#xff1a;https://github.com/yui/yuicom…

小学生开“卷”AIGC,绝不能输在起跑线上

图片来源&#xff1a;由无界AI生成 OpenAI的研究报告称&#xff0c;未来&#xff0c;大量工作岗位将受到AI冲击&#xff0c;首当其冲的岗位是作家、数学家、网页设计师、记者、律师…… 自从ChatGPT问世以来&#xff0c;人类会被AI替代的讨论甚嚣尘上&#xff0c;焦虑情绪无处不…

chatgpt赋能python:Python中的倒序遍历:如何使用Python倒序遍历?

Python中的倒序遍历&#xff1a;如何使用Python倒序遍历&#xff1f; Python是一种高级编程语言&#xff0c;它非常适合数据科学、机器学习和人工智能等领域。Python的强大之处在于它有很多内置功能&#xff0c;其中包括倒序遍历。 在本篇文章中&#xff0c;我们将介绍如何使…

EmbodiedGPT|具身智能或将成为实现AGI的最后一公里

卷友们好&#xff0c;我是穆尧。 最近由Chatgpt所引爆的新一代人工智能的革命正在如火如荼的进行&#xff0c;几乎重塑了所有的互联网产品&#xff0c;如办公软件、浏览器插件、搜索引擎、推荐系统等。这样巨大的改变&#xff0c;让大家对通用人工智能又燃起了新的希望&#xf…

CTPN文本检测详解 面试版本

二.关键idea 1.采用垂直anchor回归机制&#xff0c;检测小尺度的文本候选框 2.文本检测的难点在于文本的长度是不固定&#xff0c;可以是很长的文本&#xff0c;也可以是很短的文本&#xff0e;如果采用通用目标检测的方法&#xff0c;将会面临一个问题&#xff1a;**如何生成好…

Autosar诊断实战系列01-手把手教你增加一路31Routine服务

本文框架 1.系列概述2. UDS Routine服务添加3. DcmDspRoutine配置3.1 DcmDspRoutineInfos配置3.2 DcmDspRoutines配置1.系列概述 在本系列笔者将结合工作中对诊断实战部分的应用经验进一步介绍常用UDS服务的进一步探讨及开发中注意事项, Dem/Dcm/CanTp/Fim模块配置开发及注意…

编译tolua——2、基础编译tolua

目录 1、编译工具和环境说明 2、基础编译tolua 大家好&#xff0c;我是阿赵。 继续来讲tolua的各个常用平台的编译。 这里使用官方的tolua_runtime-master项目来做编译 具体需要的编译软件和源码地址&#xff0c;在上一篇文章已经介绍过了&#xff0c;先把环境准备好&#xff…