当前位置: 首页 > ai >正文

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

目录

  • 引言
  • 合并 K 个升序链表
    • 我的解题
    • 代码优化
      • 当前解法分析
      • 优化方案
        • 方法一:分治合并(推荐)
        • 方法二:优先队列(最小堆)
        • 方法三:优化顺序合并
      • 各方法比较
      • 推荐优化

请添加图片描述

  • 🙋‍♂️ 作者:海码007
  • 📜 专栏:算法专栏
  • 💥 标题:【Hot 100】23. 合并 K 个升序链表
  • ❣️ 寄语:书到用时方恨少,事非经过不知难!

引言

合并 K 个升序链表

  • 🎈 题目链接:
  • 🎈 做题状态:

我的解题

虽然是一个困难题,但是其实可以把问题拆分一下,每次都合并两个有序链表,然后循环从前往后合并即可。然后合并两个有序链表在前面已经写过了。

/*** 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* mergeTwoLists(ListNode* list1, ListNode* list2) {ListNode* dummy = new ListNode(0);ListNode* tail = dummy;while(true){if (list1 == nullptr || list2 == nullptr) break;if (list1->val < list2->val){tail->next = list1;list1 = list1->next;}else{tail->next = list2;list2 = list2->next;}tail = tail->next;  // 移动末尾指针}// 连接剩余的节点tail->next = list1 ? list1 : list2;return dummy->next;}ListNode* mergeKLists(vector<ListNode*>& lists) {if (lists.size() == 0) return nullptr;if (lists.size() == 1) return lists[0];// 分治思想,每次合并两个链表,然后直到合并完毕for(int i = 0; i < lists.size() - 1; ++i){lists[i + 1] = mergeTwoLists(lists[i], lists[i + 1]);}return lists[lists.size() - 1];}
};

代码优化

你的解法是顺序合并两个链表的方法,虽然正确但效率可以优化。我来分析并提供几种优化方案:

当前解法分析

  1. 时间复杂度

    • 假设k个链表,每个链表平均长度n
    • 顺序合并的时间复杂度是O(k²n)(第一次合并n+n,第二次2n+n,…,第k次(k-1)n+n)
  2. 优点

    • 实现简单直观
    • 复用已有的合并两个链表的方法
  3. 缺点

    • 重复遍历节点(前面的链表被多次合并)
    • 时间复杂度较高

优化方案

方法一:分治合并(推荐)

将k个链表两两分组合并,再合并结果,时间复杂度O(kn logk)

class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {ListNode dummy(0);ListNode* tail = &dummy;while (l1 && l2) {if (l1->val < l2->val) {tail->next = l1;l1 = l1->next;} else {tail->next = l2;l2 = l2->next;}tail = tail->next;}tail->next = l1 ? l1 : l2;return dummy.next;}ListNode* mergeKLists(vector<ListNode*>& lists) {if (lists.empty()) return nullptr;int interval = 1;while (interval < lists.size()) {for (int i = 0; i + interval < lists.size(); i += 2 * interval) {lists[i] = mergeTwoLists(lists[i], lists[i + interval]);}interval *= 2;}return lists[0];}
};
方法二:优先队列(最小堆)

使用优先队列每次取出最小节点,时间复杂度O(kn logk)

class Solution {
public:struct Compare {bool operator()(ListNode* a, ListNode* b) {return a->val > b->val;}};ListNode* mergeKLists(vector<ListNode*>& lists) {priority_queue<ListNode*, vector<ListNode*>, Compare> pq;// 初始化优先队列for (auto list : lists) {if (list) pq.push(list);}ListNode dummy(0);ListNode* tail = &dummy;while (!pq.empty()) {ListNode* node = pq.top();pq.pop();tail->next = node;tail = tail->next;if (node->next) {pq.push(node->next);}}return dummy.next;}
};
方法三:优化顺序合并

调整合并顺序,减少重复遍历

class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {// 保持你的原有实现}ListNode* mergeKLists(vector<ListNode*>& lists) {if (lists.empty()) return nullptr;// 每次合并相邻的两个链表,然后缩小范围int len = lists.size();while (len > 1) {for (int i = 0; i < len / 2; ++i) {lists[i] = mergeTwoLists(lists[i], lists[len - 1 - i]);}len = (len + 1) / 2;}return lists[0];}
};

各方法比较

方法时间复杂度空间复杂度实现难度适用场景
顺序合并O(k²n)O(1)简单k较小时
分治合并O(kn logk)O(logk)中等通用最优解
优先队列O(kn logk)O(k)中等需要流式处理时
优化顺序合并O(kn logk)O(1)中等避免递归栈空间时

推荐优化

  1. 首选分治合并:时间最优且空间效率好
  2. 次选优先队列:代码更直观,但空间稍高
  3. 避免简单顺序合并:时间复杂度太高

你的原始解法可以轻松升级为分治合并方案,只需修改合并策略即可获得显著性能提升。

http://www.xdnf.cn/news/3304.html

相关文章:

  • 【深度学习新浪潮】小米MiMo-7B报告内容浅析
  • MATLAB中removedelay函数用法
  • 区间贪心 (区间端点处理)
  • llamafactory-cli webui启动报错TypeError: argument of type ‘bool‘ is not iterable
  • 《AI大模型应知应会100篇》第41篇:多轮对话设计:构建高效的交互式应用
  • CentOS 7 下安装 supervisor-3.4.0-1.el7.noarch.rpm 详细步骤
  • QMK固件开发指南:构建您的第一个固件
  • 22.2Linux的I2C驱动实验(编程)_csdn
  • 2024年12月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试
  • Qt指南针
  • 9. 深入Spring AI:刨析 ChatMemory
  • 从MCP基础到FastMCP实战应用
  • 攻防世界 - Web - Level 4 | Confusion1
  • qemu学习笔记:QOM
  • AWS CloudFront全球加速利器:解析出海业务的核心优势与最佳实践
  • 2025五一数学建模ABC题选题建议,思路模型分析
  • Hive数据倾斜 常见解决办法
  • 深度学习框架搭建(Vscode/Anaconda/CUDA/Pytroch)
  • 基于单片机的音频信号处理系统设计(三)
  • LangChain简明教程(12)
  • Ubuntu 安装 Cursor
  • donet使用指定版本sdk
  • Python数据分析课程实验-2
  • C#类访问修饰符
  • 经济学和奥地利学派的起源
  • WEB UI自动化测试之Selenium框架学习
  • 面试中系统化地解答系统设计题:通用方法论
  • Unity图片导入设置
  • C++11新特性_范围-based for 循环
  • 五一北方穿外套:南方要防暑