力扣第23题:合并K个升序链表

详解力扣第23题:合并K个升序链表

题目描述

给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。

本题可以通过优先队列-最小堆来高效解决,因为我们需要频繁地找到当前K个链表中值最小的元素,并进行合并。

最小堆思路

最小堆是一种完全二叉树结构,可以在O(logK) 的时间复杂度内完成插入和删除操作,适用于需要频繁寻找最小值的场景。对于本题,使用最小堆可以有效减少每次查找最小节点的时间,从而加速链表合并的过程。

代码详解

1. 数据结构定义

我们使用链表节点(ListNode)结构来表示输入的链表。MinHeap 结构用于实现最小堆。

#include <stdio.h>
#include <stdlib.h>

// 定义链表结构体
struct ListNode {
    int val;
    struct ListNode *next;
};

// 定义最小堆的结构体
struct MinHeap {
    struct ListNode **array;
    int size;
};
  • ListNode:链表节点,val 存储节点值,next 指向下一个节点。
  • MinHeap:最小堆,array 存储指向链表节点的指针数组,size 表示堆中节点的数量。

2. 创建最小堆

// 创建一个新的最小堆节点
struct MinHeap* createMinHeap(int k) {
    struct MinHeap* heap = (struct MinHeap*)malloc(sizeof(struct MinHeap));
    heap->array = (struct ListNode**)malloc(k * sizeof(struct ListNode*));
    heap->size = 0;
    return heap;
}

3. 堆操作

上浮操作
// 将堆元素进行上浮
void heapifyUp(struct MinHeap* heap, int idx) {
    while (idx > 0 && heap->array[(idx - 1) / 2]->val > heap->array[idx]->val) {
        struct ListNode* temp = heap->array[idx];
        heap->array[idx] = heap->array[(idx - 1) / 2];
        heap->array[(idx - 1) / 2] = temp;
        idx = (idx - 1) / 2;
    }
}

上浮操作用于插入元素时保持最小堆的性质,将新元素与父节点比较,并逐步上移至合适的位置。

下沉操作
// 将堆元素进行下沉
void heapifyDown(struct MinHeap* heap, int idx) {
    int smallest = idx;
    int left = 2 * idx + 1;
    int right = 2 * idx + 2;

    if (left < heap->size && heap->array[left]->val < heap->array[smallest]->val) {
        smallest = left;
    }

    if (right < heap->size && heap->array[right]->val < heap->array[smallest]->val) {
        smallest = right;
    }

    if (smallest != idx) {
        struct ListNode* temp = heap->array[idx];
        heap->array[idx] = heap->array[smallest];
        heap->array[smallest] = temp;
        heapifyDown(heap, smallest);
    }
}

下沉操作用于删除最小元素后保持堆的性质,将最后一个元素移动到根节点后,通过下沉操作恢复最小堆。

插入与删除最小元素
// 向堆中插入新元素
void insertMinHeap(struct MinHeap* heap, struct ListNode* node) {
    heap->array[heap->size] = node;
    heapifyUp(heap, heap->size);
    heap->size++;
}

// 从堆中取出最小元素
struct ListNode* extractMin(struct MinHeap* heap) {
    struct ListNode* root = heap->array[0];
    heap->array[0] = heap->array[heap->size - 1];
    heap->size--;
    heapifyDown(heap, 0);
    return root;
}

4. 合并K个链表

// 合并K个升序链表
struct ListNode* mergeKLists(struct ListNode** lists, int k) {
    struct MinHeap* heap = createMinHeap(k);

    for (int i = 0; i < k; i++) {
        if (lists[i] != NULL) {
            insertMinHeap(heap, lists[i]);
        }
    }

    struct ListNode dummy;
    struct ListNode* tail = &dummy;
    dummy.next = NULL;

    while (heap->size > 0) {
        struct ListNode* minNode = extractMin(heap);
        tail->next = minNode;
        tail = tail->next;

        if (minNode->next != NULL) {
            insertMinHeap(heap, minNode->next);
        }
    }

    return dummy.next;
}

在这里,我们将每个链表的第一个节点插入最小堆中,每次取出堆中的最小节点,将其插入到最终合并后的链表中,并将该节点的下一个节点继续插入堆中。

5. 测试代码

// 创建新节点
struct ListNode* createNode(int val) {
    struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    newNode->val = val;
    newNode->next = NULL;
    return newNode;
}

// 打印链表
void printList(struct ListNode* head) {
    while (head != NULL) {
        printf("%d ", head->val);
        head = head->next;
    }
    printf("\n");
}

// 主函数
int main() {
    // 创建测试用例:[[1,4,5],[1,3,4],[2,6]]
    struct ListNode* list1 = createNode(1);
    list1->next = createNode(4);
    list1->next->next = createNode(5);

    struct ListNode* list2 = createNode(1);
    list2->next = createNode(3);
    list2->next->next = createNode(4);

    struct ListNode* list3 = createNode(2);
    list3->next = createNode(6);

    struct ListNode* lists[] = {list1, list2, list3};

    // 合并链表
    struct ListNode* result = mergeKLists(lists, 3);

    // 打印结果
    printf("合并后的链表: ");
    printList(result);

    return 0;
}

输出结果:

合并后的链表: 1 1 2 3 4 4 5 6 

最小堆插入与删除操作图解

1. 初始状态

假设我们有三个链表,每个链表的第一个元素分别是 112,插入最小堆的初始状态如下:

        1
       / \
      1   2

2. 删除最小元素

当我们删除堆顶最小元素(值为1)时,将 2 替换到根节点,进行下沉操作:

        1
       / \
      2

继续从对应链表插入下一个节点,重复此过程直到所有链表都被合并。


通过最小堆实现,合并 K 个升序链表的时间复杂度为 O(NlogK),其中 N 是所有链表的节点总数,K 是链表的个数。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT找不到ffmpeg链接库解决方法

error: undefined reference to avformat_network_init() 一个神奇的报错&#xff0c;查了很久&#xff0c;检查步骤&#xff1a; 1、检查了 pro工程文件 2、链接库的真实性和正确性 在main.cpp中调用没有报错&#xff0c;在其它cpp文件中调用就报错。 破案了&#xff0c;…

详细了解C++11(1)

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各…

04.DDD与CQRS

学习视频来源&#xff1a;DDD独家秘籍视频合集 https://space.bilibili.com/24690212/channel/collectiondetail?sid1940048&ctype0 文章目录 定义职责分离DDD与CQRS的关系领域模型和查询模型特点命令场景的领域模型查询场景的查询模型 架构方案领域事件方案1&#xff1a…

【运动的&高尔夫球】高尔夫球检测系统源码&数据集全套:改进yolo11-CA-HSFPN

改进yolo11-HWD等200全套创新点大全&#xff1a;高尔夫球检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.30 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视频可…

【python】flash-attn安装

这个命令&#xff1a; 确保使用正确的 CUDA 12.6 工具链 设置必要的 CUDA 环境变量 包含了常见的 GPU 架构支持 利用你的128核心进行并行编译 # 清理之前的安装 proxychains4 pip uninstall -y flash-attn# 获取 CUDA 路径 CUDA_PATH$(dirname $(dirname $(which nvcc)))# 使用…

得计算题者得天下!软考系统集成计算题详解!

软考中级系统集成项目管理工程师考试一共有《综合知识》和《案例分析》两门科目&#xff0c;而在这两科中都会涉及到计算题&#xff0c;特别是案例分析中&#xff0c;计算题每次考试都会占到一道大题&#xff0c;共25分&#xff0c;占到了科目总分的1/4&#xff0c;所以对于系统…

第2章 Android App开发基础

第 2 章 Android App开发基础 bilibili学习地址 github代码地址 本章介绍基于Android系统的App开发常识&#xff0c;包括以下几个方面&#xff1a;App开发与其他软件开发有什么不一 样&#xff0c;App工程是怎样的组织结构又是怎样配置的&#xff0c;App开发的前后端分离设计…

腾讯云视频文件上传云存储时自动将mp4格式转码成m3u8

针对问题&#xff1a; 弱网环境下或手机网络播放mp4格式视频卡顿。 存储环境&#xff1a;腾讯云对象存储。 处理流程&#xff1a; 1&#xff1a;登录腾讯云控制台&#xff0c;进入对象存储服务&#xff0c;找到对应的存储桶&#xff0c;点击进入。 在任务与工作流选项卡中找…

如何下载安装TestLink?

一、下载TestLink、XAMPP TestLink 下载 |SourceForge.net 备用&#xff1a;GitHub - TestLinkOpenSourceTRMS/testlink-code&#xff1a; TestLink开源测试和需求管理系统 下载XAMPP&#xff1a; Download XAMPP 注意&#xff1a;TestLink与PHP版本有关系&#xff0c;所以XA…

【AI学习】扩散模型的一点思考:生成过程为什么要增加噪声项

前面学习了扩散模型&#xff0c;并做了总结PPT。 其中有一个疑问&#xff1a;在生成过程中&#xff0c;就是下图的算法2中的第四步&#xff0c;为什么要在预测了噪声项后&#xff0c;Xt减去预测的噪声后&#xff0c;还有再叠加一个噪声项&#xff1f;就是增加的部分。 李宏毅…

Halcon 多相机统一坐标系(标定)

多相机统一坐标系是指将多个不同位置的相机的图像采集到同一个坐标系下进行处理和分析的方法。 在计算机视觉和机器视觉领域中&#xff0c;多相机统一坐标系被广泛应用于三维重建、立体视觉、目标跟踪等任务中。 以gen_binocular_rectification_map&#xff08;生成描述图像映…

访问jenkins页面报错

安装fontconfig 即可 yum install fontconfig -y 安装完之后重启jenkins systemctl restart jenkins 再访问

安卓13 连接usb设备后不更新ui

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码更改4.彩蛋1.前言 有些界面在链接usb设备后,ui会被刷新,导致闪烁问题。 2.问题分析 像这种问题一般是usb事件,导致的ui事件更新了,处理方法是禁止该事件 3.代码更改 这块我们就需要在输入事件管理里面…

从变量的角度理解 Hooks , 变得更简单了

从变量角度理解Hooks 在React的世界里&#xff0c;Hooks的引入为函数式组件带来了前所未有的灵活性和能力。它们让我们得以完全摆脱class式的写法&#xff0c;在函数式组件中完成生命周期管理、状态管理、逻辑复用等几乎全部组件开发工作。这次&#xff0c;我们就从变量的角度…

【面试经典150】day 9

目录 1.Z 字形变换 2.找出字符串中第一个匹配项的下标 3.文本左右对齐 1.Z 字形变换 class Solution {public String convert(String s, int numRows) {//明明是N字形变换if(numRows<2) return s;//rows是可扩展的字符串数组List<StringBuilder>rowsnew ArrayLi…

sudo apt install jupyter-notebook安装notebook失败E: Aborting install.

问题&#xff1a; sudo apt install jupyter-notebook安装notebook失败E: Aborting install. ~/jie/mywork/PointNetCFD$ sudo apt install jupyter-notebook --fix-missing Reading package lists... Done Building dependency tree Reading state information... Do…

软件工程实践项目:人事管理系统

一、项目的需求说明 通过移动设备登录app提供简单、方便的操作。根据公司原来的考勤管理制度&#xff0c;为公司不同管理层次提供相应的权限功能。通过app上面的各种标准操作&#xff0c;考勤管理无纸化的实现&#xff0c;使公司的考勤管理更加科学规范&#xff0c;从而节省考…

AI与低代码的碰撞:企业数字化转型的新引擎

引言 在当今的商业环境中&#xff0c;企业数字化转型已从选择题变成了必答题。面对日益复杂的市场竞争和不断变化的客户需求&#xff0c;传统的开发模式常常显得力不从心——开发周期冗长、技术门槛高、成本居高不下&#xff0c;企业很难快速响应市场变化。而在这种背景下&…

WPF中实现PasswordBox的双向绑定

我们知道一个属性想要实现双向绑定&#xff0c;最基本的便是这个属性需要时依赖属性&#xff0c;但是微软工程师在设计的时候Password并不是依赖属性&#xff0c;那我们想要实现双向绑定该怎么去做呢&#xff1f; 最常用的便是改造PasswordBox,为它增加一个扩展属性&#xff0c…

聚链成网,趣链科技参与 “跨链创新联合体”建设

近日&#xff0c;2024全球数商大会在上海举办。大会由上海数据集团和上海市数商协会联合主办&#xff0c;上海市数据局和浦东新区人民政府支持&#xff0c;以“数联全球&#xff0c;商通未来——‘链’接数字经济新未来”为主题&#xff0c;聚焦区块链技术和应用场景展开。 会上…