leetcode hot100-34 合并K个升序链表

news/2025/2/23 6:09:22

方法一:分治法(相当于对暴力法的优化)

class Solution {
private:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* dummyhead = new ListNode(0);
        ListNode* cur = dummyhead;
        while (list1 && list2) {
            if (list1->val < list2->val) {
                cur->next = list1;
                list1 = list1->next;
            } else {
                cur->next = list2;
                list2 = list2->next;
            }
            cur = cur->next;
        }
        cur->next = list1 ? list1 : list2;
        return dummyhead->next;
    }

    ListNode* mergeKLists(vector<ListNode*>& lists, int i, int j) {
        int m = j - i;
        // 计算当前范围 [i, j) 之间的链表数量
        if (m == 0) {
            return nullptr; // 注意输入的 lists 可能是空的
        }
        if (m == 1) {
            return lists[i]; // 无需合并,直接返回
        }
        ListNode* left = mergeKLists(lists, i, i + m / 2);
        ListNode* right = mergeKLists(lists, i + m / 2, j);
        return mergeTwoLists(left, right);
    }

public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return mergeKLists(lists, 0, lists.size());
    }
};

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]

mergeKLists(0, 3)
├── mergeKLists(0, 1) → 返回 lists[0] (1 -> 4 -> 5)
└── mergeKLists(1, 3)
    ├── mergeKLists(1, 2) → 返回 lists[1] (1 -> 3 -> 4)
    ├── mergeKLists(2, 3) → 返回 lists[2] (2 -> 6)
    └── mergeTwoLists(lists[1], lists[2]) → (1 -> 2 -> 3 -> 4 -> 6)
└── mergeTwoLists(lists[0], merge(lists[1], lists[2])) → (1 -> 1-> 2 -> 3 -> 4 -> 4-> 5 -> 6)

方法二:最小堆 / 优先级队列 priority_queue 

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        auto cmp = [](const ListNode* a, const ListNode* b) {
            return a->val > b->val;
        };

        priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> pq;

        for (auto head : lists) {
            if (head) {
                pq.push(head);
            }
        }

        ListNode* dummyhead = new ListNode(0);
        ListNode* cur = dummyhead;
        while (!pq.empty()) {
            ListNode* node = pq.top();
            pq.pop();
            if (node->next) {
                pq.push(node->next);
            }
            cur->next = node;
            cur = cur->next;
        }
        ListNode* newhead = dummyhead->next;
        delete dummyhead;
        return newhead;
    }
};

这里使用 Lambda 表达式,Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使用,比如可以将它们赋给变量和作为参数传递,还可以像函数一样对其求值。Lambda 表达式本质上与函数声明非常类似。Lambda 表达式具体形式如下:

[capture](parameters)->return-type{

body

};

[捕获列表](参数列表) -> 返回类型 {
    // 函数体
};

其中:

  • [捕获列表]:捕获外部变量的方式([] 表示不捕获任何变量,[=] 表示按值捕获,[&] 表示按引用捕获)。

  • (参数列表):定义传递给 Lambda 的参数(类似普通函数的参数)。

  • -> 返回类型(可选):指定返回值类型(可以省略,由编译器推导)。

  • { 函数体 }:函数的具体实现。

这道题目中:

(1)定义 Lambda

[](ListNode* a, ListNode* b) { return a->val > b->val; }

(2)decltype(cmp) 用于自动推导 cmp 的类型,因为lambda没有名字。这样 priority_queue 就能正确使用 cmp进行排序。

(3)初始化 priority_queue,

priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> pq(cmp);

  • ListNode* 是存储的数据类型。

  • vector<ListNode*> 是底层实现(默认 vector)。

  • decltype(cmp) 指定比较器的类型,pq(cmp) 传入 cmp 作为构造函数参数。

当然也可以使用operator() 仿函数,对 () 进行重载

struct compare {
        bool operator()(ListNode* a, ListNode* b) { 
            return a->val > b->val; 
        }
    };


priority_queue<ListNode*, vector<ListNode*>, compare> pq;
class Solution {
public:
    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 (auto head : lists) {
            if (head) {
                pq.push(head);
            }
        }
        ListNode* dummyhead = new ListNode(0);
        ListNode* cur = dummyhead;
        while (!pq.empty()) {
            ListNode* node = pq.top();
            pq.pop();
            if (node->next) {
                pq.push(node->next);
            }
            cur->next = node;
            cur = cur->next;
        }
        ListNode* newhead = dummyhead->next;
        delete dummyhead;
        return newhead;
    }
};

operator() vs 普通函数

你可能会问:为什么不用普通函数,而要用 operator()

(1)普通函数:

bool myCompare(ListNode* a, ListNode* b) {
    return a->val > b->val;
}

priority_queue<ListNode*, vector<ListNode*>, decltype(&myCompare)> pq(myCompare);

 也可以,但 myCompare 需要用 &myCompare 传递,略显繁琐。使用 &myCompare,表示传递的是函数指针

(2)使用 operator()(仿函数):

struct compare {
    bool operator()(ListNode* a, ListNode* b) {
        return a->val > b->val;
    }
};
priority_queue<ListNode*, vector<ListNode*>, compare> pq;

 更简洁priority_queue 直接使用 compare 作为类型

(3)使用 lambda(C++11):

auto cmp = [](ListNode* a, ListNode* b) { return a->val > b->val; };
priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> pq(cmp);

 最简洁,省去 struct compare 定义,适用于单次使用。

 

 

 


http://www.niftyadmin.cn/n/5863076.html

相关文章

bpmn.js + Node.js_构建高效的后端工作流处理系统

1. 引言 1.1 研究背景与意义 随着企业业务的复杂化,传统的流程管理工具已难以满足需求。BPMN(Business Process Model and Notation)作为一种标准化的流程建模语言,结合 bpmn.js 和 Node.js 可以实现高效的工作流管理系统,提升企业的运营效率。 1.3 BPMN 和 bpmn.js 简…

最新版本Exoplayer(MediaX)实现K歌原伴唱包括单音轨和双音轨

在做K歌类项目中&#xff0c;原伴唱切换是必不可少的基础功能&#xff0c;一般一首完整的歌曲要包含MV视频原唱音频伴唱音频歌词。 而原伴唱音频有两种形式&#xff1a; 1.双音轨&#xff1a;音轨一是原唱&#xff0c;音轨二是伴唱 2.单音轨&#xff1a;左声道是原唱&#x…

Web自动化中Selenium下Chrome与Edge的Webdriver常用Options参数

目录 引言 说明 Add_argument() 添加方式 常用参数 Add_experimental_option() 添加方式 常用方法 任务结束后仍然保持浏览器打开 禁用“Chrome 正受到自动测试软件的控制”提示 设置下载路径 禁用弹窗拦截 禁用图片加载 禁用 JavaScript 注意 引言 …

UITextView删除原有字符串时,光标会上移并且光标会变高

代码运行效果如图&#xff1a; import Foundationclass TestVC: UIViewController {override func viewDidLoad() {super.viewDidLoad()let testV MyCustomTextView(frame: CGRect(x: 0, y: 130, width: SCREEN_WIDTH - 50, height: 170))self.view.addSubview(testV)testV.ba…

23种设计模式之《桥接模式(Bridge)》在c#中的应用及理解

程序设计中的主要设计模式通常分为三大类&#xff0c;共23种&#xff1a; 1. 创建型模式&#xff08;Creational Patterns&#xff09; 单例模式&#xff08;Singleton&#xff09;&#xff1a;确保一个类只有一个实例&#xff0c;并提供全局访问点。 工厂方法模式&#xff0…

近地面无人机遥感:如何利用高光谱数据反演植被生理参数?

文章目录 前言专题一、近十年近地面无人机植被遥感文献分析、传感器选择、观测方式及质量控制要点1.1. 近十余年无人机植被遥感文献分析1.2. 无人机遥感的特点及与卫星遥感的差异1.3. 无人机传感器类型、特点及选择1.4. 无人机遥感观测方式、特点与质量控制 二、辐射度量与地物…

buu-ciscn_2019_n_5-好久不见41

由于目标程序的 BSS 段&#xff08;包含 name 变量&#xff09;权限是全开的&#xff08;可读、可写、可执行&#xff09;&#xff0c;并且没有启用 NX&#xff08;No Execute&#xff0c;非执行&#xff09;保护机制&#xff0c;因此可以直接在 BSS 段上构造 Shellcode&#x…

Eclipse2024中文汉化教程(图文版)

对应Eclipse,部分人需要中文汉化,本章教程,介绍如何对Eclipse进行汉化的具体步骤。 一、汉化前的Eclipse 默认安装Eclipse的时候,默认一般都是English的,我当前版本是使用的是2024-06版本的Eclipse。 二、汉化详细步骤 点击上方菜单选项卡,Hep——Install New Software……