这道题要求合并K个有序链表,题面如下。
合并两个已排序链表是这类问题的一个基本问题,但是当链表数目从2变成K时,如何寻找下一个要插入的结点就变成了一个最重要的问题。可以通过每次遍历每个链表开头的结点来得到(复杂度O(k))当前应该插入的最小值的结点,但是这样的复杂性太高。所以这道题必须引入一个数据结构来帮助我们快速筛选出要插入的下一个结点,我选择的是优先级队列(priority_queue)。当然,因为实现优先级队列的STL底层数据结构是堆,所以与手写一个堆来做效果是一致的。
关于C++中的优先级队列,详细用法可以参考这篇博客priority_queue的用法,学习的重点主要是看如何设定队列中元素的优先级,可以重载运算符<,也可以写一个仿函数ftor,我在本题的代码中使用的是重载运算符。非常重要的一点是,要注意返回值和实际排序的对应关系,它和sort中的直觉是相反的。
所以首先定义一个类QueueElement,其中保存了结点值和对应结点的指针:
/*define a struct*/
struct QueueElement
{
int Val; /*value of a node*/
ListNode* Ptr; /*pointer to the node*/
QueueElement(int V, ListNode* P):Val(V), Ptr(P){} /*constructor*/
bool operator < (const QueueElement& Other) const /*override the operator <*/
{
return Val > Other.Val; /*watch out the order*/
}
};
随后定义一个关于QueueElement的优先级队列,这个队列会替我们管理当前的结点序列,保证top()函数会返回当前的最小结点。
完整代码如下:
/**
* 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 {
/*define a struct*/
struct QueueElement
{
int Val; /*value of a node*/
ListNode* Ptr; /*pointer to the node*/
QueueElement(int V, ListNode* P):Val(V), Ptr(P){} /*constructor*/
bool operator < (const QueueElement& Other) const /*override the operator <*/
{
return Val > Other.Val;
}
};
/*
merge a new node to Result list, return the pointer
pointing to the next node of Node
*/
ListNode* mergeNode(ListNode*& Res, ListNode* Node)
{
Res->next = Node;
Res = Node;
return Res->next; /*the pointer should be pushed into queue immediately*/
}
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
/*apply for a dummy node*/
ListNode* DummyNode = new ListNode(-1);
ListNode* Present = DummyNode;
/*a priority queue*/
priority_queue<QueueElement> Q;
/*push all the node pointer to the queue*/
for(int i = 0 ; i < lists.size() ; ++i)
{
if(lists[i])
{
QueueElement Temp(lists[i]->val, lists[i]);
Q.push(Temp);
}
}
while(!Q.empty())
{
/*pop the node with the smallest value*/
QueueElement Front = Q.top();
Q.pop();
/*connect the front node to the result list*/
ListNode* NewHead = mergeNode(Present, Front.Ptr);
if(NewHead) /*not null*/
{
/*push the new node to queue immediately*/
QueueElement Temp(NewHead->val, NewHead);
Q.push(Temp);
}
}
return DummyNode->next;
}
};