Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
本题在上一题(LeetCode 21: Merge Two Sorted Lists)基础上再加深了一步,链表个数从两个改为K个。
此题有如下几种解法:
1、最简单的方法莫过于每次都从K个链表头中找到最小的那个元素,加入结果链表中。基于此,有人通过最小堆来简化最小元素的比较。
struct CompareListNode{
bool operator()(const ListNode*p, const ListNode* q)const{
return p->val > q->val;
}
};
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode head(-1);
vector<ListNode*> vec_helper;
//除去空链表
for (int i=0; i<lists.size(); i++)
{
if (lists[i]!=NULL)
vec_helper.push_back(lists[i]);
}
//建小堆
std::make_heap(vec_helper.begin(), vec_helper.end(), CompareListNode());
ListNode* pTail = &head;
while (vec_helper.size() > 0)
{
//取最小的元素对应的节点
ListNode *pNode = vec_helper.front();
pTail->next= pNode;
pTail = pTail->next;
std::pop_heap(vec_helper.begin(), vec_helper.end(), CompareListNode());
vec_helper.pop_back();
//将该节点之后一个节点加堆中
if (pNode->next)
{
vec_helper.push_back(pNode->next);
std::push_heap(vec_helper.begin(), vec_helper.end(), CompareListNode());
}
}
pTail->next = NULL;
return head.next;
}
};
同样还有基于优先队列的算法:
ListNode* mergeKLists3(vector<ListNode*>& lists) {
int length = lists.size();
ListNode head(-1);
ListNode* pTail = &head;
priority_queue<ListNode*, vector<ListNode*>, CompareListNode> list_queue;
for (int i=0; i<length; i++)
{
if (lists[i])
list_queue.push(lists[i]);
}
while (list_queue.size() >0)
{
ListNode* ptmpNode = list_queue.top();
list_queue.pop();
pTail->next = ptmpNode;
pTail = pTail->next;
if (ptmpNode->next)
list_queue.push(ptmpNode->next);
}
pTail->next = NULL;
return head.next;
}
2、每次从数组中取两个链表,将合并结果加入到链表中,反复这个过程,直到数组中只剩一个链表为止,对两个链表进行合并的代码可以复用LeetCode21的代码。
ListNode* mergeKLists2(vector<ListNode*>& lists) {
int length = lists.size();
if (length == 0)
return NULL;
while (lists.size() >1)
{
ListNode* p1 = lists.front ();
lists.erase(lists.begin());
ListNode* p2 = lists.front();
lists.erase(lists.begin());
lists.push_back(mergeTwoLists(p1, p2));
}
return lists[0];
}
3、将数组拆分成左、右两个子数组,递归的对左、右两个子数组进行合并,再将合并得到的两个链表合并在一起。
方法3比较简洁
复用上题两个链表的合并代码,方法3的实现代码如下:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int length = lists.size();
if (length == 0) {
return NULL;
} else if(length == 1)
return lists[0];
else if(length == 2) {
return mergeTwoLists(lists[0], lists[1]);
}
vector<ListNode*> leftHalf(lists.begin(), lists.begin()+length/2);
vector<ListNode*> rightHalf(lists.begin()+length/2, lists.end());
return mergeTwoLists(mergeKLists(leftHalf), mergeKLists(rightHalf));
}