题目
合并K个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
解答思路
这是我在QQ群看到别人刷到这题,他说这题和算法导论里面的习题6.9一模一样。我特意去算法导论里面找,然后看到了这题:
惭愧,我之前看算法导论的时候就没做后面的习题,这题居然在leetcode标为困难。所有我利用最小优先队列来做这道题。
解题思路:将K个排序链表的第一个结点构建小顶堆,这样确保每次取K个链表中最小的结点时间复杂度为常数1,每次取一个结点,该结点之后的结点填充该结点位置,然后维护堆的性质,维护堆的性质时间复杂度为log(k),取完一条链表之后,堆长度减一,维护堆的性质。这样总共需要取n个结点,每次取结点的时间复杂度为1,每次取完都要维护堆的性质,维护堆的时间复杂度为log(k),所以总的时间复杂度为nlog(k)。
如果你用暴力求解,每次遍历K个链表取最小的出来,那么时间复杂度为n*k。
C++代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
int getParent(int i) { return i == 0 ? i : (i - 1) >> 1; }
int getleft(int i) { return ((i + 1) << 1) - 1; }
int getright(int i) { return (i + 1) << 1; }
void fixupHeap(vector<ListNode*>& lists, int i, int heapSize) {
if (i >= heapSize) { return; }
int min = i;
if (getleft(i) < heapSize && lists.at(min)!=0 && lists.at(getleft(i))!=0 &&lists.at(min)->val > lists.at(getleft(i))->val ) {
//swap(lists.at(i), lists.at(getleft(i)));
min = getleft(i);
}
if (getright(i) < heapSize && lists.at(min)!=0 && lists.at(getright(i))!=0 && lists.at(min)->val > lists.at(getright(i))->val ) {
//swap(lists.at(i), lists.at(getright(i)));
min = getright(i);
}
if (min != i) {
swap(lists.at(i), lists.at(min));
fixupHeap(lists, min, heapSize);
}
}
void buildHeap(vector<ListNode*>& lists,int* heapSize) {
for (int i = 0; i < (*heapSize); i++)
{
if (lists.at(i) == 0) {
swap(lists.at(i), lists.at((*heapSize) - 1));
--(*heapSize);
--i;
}
}
for (int i = lists.size() / 2; i >= 0; i--) {
fixupHeap(lists, i, lists.size());
}
}
ListNode* ExcMin(vector<ListNode*>& lists, int* heapSize) {
ListNode* res = 0;
if ((*heapSize) < 1) { return res; }
else if ((*heapSize) == 1) {
res = lists.at(0);
if(lists.at(0)->next == 0){
--(*heapSize);
}else{
lists.at(0) = lists.at(0)->next;
}
return res;
}
else {
res = lists.at(0);
if (lists.at(0)->next != 0) {
lists.at(0) = lists.at(0)->next;
}
else {
swap(lists.at(0), lists.at((*heapSize)-1));
--(*heapSize);
}
fixupHeap(lists, 0, *heapSize);
}
return res;
}
ListNode* GetMin(vector<ListNode*>& lists, int* heapSize) {
ListNode* res = 0;
if ((*heapSize) < 1) { return res; }
else {
res = lists.at(0);
return res;
}
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
int size = lists.size();
int* heapSize = &size;
buildHeap(lists,heapSize);//创建小顶堆
ListNode* p = ExcMin(lists, heapSize);
ListNode* root = p;
while (GetMin(lists, heapSize) != 0) {
ListNode* q = ExcMin(lists, heapSize);
p->next = q;
p = q;
}
if(p != 0){
p->next = 0;
}
return root;
}
};