【数据结构-堆】【hard】力扣23. 合并 K 个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

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

输出:1,1,2,3,4,4,5,6

解释:链表数组如下:

1-\>4-\>5, 1-\>3-\>4, 2-\>6

将它们合并到一个有序链表中得到。

1->1->2->3->4->4->5->6

示例 2:

输入:lists = \[\]

输出:\[\]

示例 3:

输入:lists = \[]

输出:\[\]

优先队列

csharp 复制代码
//正常情况优先队列如果true,表示当前元素比右侧元素小,将右侧元素放到堆顶,实现大根堆。
//改变operator后,当前元素比右侧元素大堆时候true,将右侧元素放到堆顶,实现小根堆。
class Solution {
public:
    struct Status {
        int val;
        ListNode *ptr;
        bool operator < (const Status &rhs) const {
            return val > rhs.val;
        }
    };

    priority_queue <Status> q;

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        for (auto node: lists) {
            if (node) q.push({node->val, node});
        }
        ListNode head, *tail = &head;
        while (!q.empty()) {
            auto f = q.top(); q.pop();
            tail->next = f.ptr; 
            tail = tail->next;
            if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});
        }
        return head.next;
    }
};

时间复杂度 :考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn×logk)。
空间复杂度:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。

我们定义了一个结构体Status,修改了他的比较器。正常情况优先队列如果true,表示当前元素比右侧元素小,将右侧元素放到堆顶,实现大根堆。
改变operator后,当前元素比右侧元素大堆时候true,将右侧元素放到堆顶,实现小根堆。

这道题是关于链表的题,题目要求合并k个升序链表,实际上我们就可以有这么一个思路:我们将每个链表的元素都丢入小根堆中,然后将小根堆的元素依次组成一个新的链表。由于题目中已经升序排列好每个链表,也就是说每个链表的头节点的val是链表中最小的。

首先我们先将lists中每个链表头节点push到小根堆q中,然后我们定义一个新链表头节点head,还有一个指针tail用来指向链表的尾部。接下来我们不断循环,f代表的是小根堆中的堆顶头节点,即val最小,我们将他连接到我们新建的链表尾部tail->next = f.ptr;,接着更新tail的位置tail = tail->next;使其在队尾。接着我们检查f节点的链表中是否还有其他节点,如果f.ptr->next存在,就将其连接的下一个节点推入到小根堆中,以便进行比较后插入到新建合并链表的合适位置。

最后返回head.next,这是因为head只是虚拟的头节点。

以及为什么我们不直接将节点的val一次性全部放入q中呢?因为当q的元素不断增加,插入的时间复杂度也在增加。堆的插入操作需要将元素插入到堆的最底层,并通过"上浮"操作将该元素移动到正确的位置。这个过程需要的时间复杂度是 O(log k),其中 k 是堆中元素的数量。

相关推荐
CSharp精选营2 天前
关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
数据结构·nosql·关系型数据库·非关系型数据库·技术选型
To_OC3 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode
To_OC3 天前
LC 208 实现 Trie 前缀树:曾被名字劝退,写完发现是送分题
javascript·算法·leetcode
To_OC4 天前
LC 994 腐烂的橘子:人人都说是 BFS 入门题,我却写了三遍才过
javascript·算法·leetcode
To_OC4 天前
LC 200 岛屿数量:经典 DFS 入门题,我第一次写居然连方向都搞错了
javascript·算法·leetcode
To_OC5 天前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
刘马想放假5 天前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
北域码匠6 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法
To_OC7 天前
LC 49 字母异位词分组:想到哈希表很简单,选对 key 才是精髓
javascript·算法·leetcode
To_OC8 天前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode