合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
思路:这道题的基本思路是选取k个列表,每次找出列表中最小的元素拼接到新的列表中,这样逐个拼接便可以实现合并后的排序链表。假设所有的节点个数是N,而找出k个列表中最小的元素需要k次比较,所以综合复杂度是:kN。如果采用优先队列,队列的元素是pair<int,ListNode*>,int是列表的指针对应的值,ListNode*是每个列表的指针(相当于队列当前遍历的下标)。由于优先队列的比较次数是log(k),所以时间复杂度降到了nlogk。
参考代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
struct tmp {
bool operator()(pair<int, ListNode*> a,pair<int, ListNode*> b) {
return a.first > b.first;
}
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* pre_head = new ListNode(-1);
ListNode* t = pre_head;
priority_queue<pair<int, ListNode*>, vector<pair<int, ListNode*>>, tmp> pq;
for (int i = 0; i < lists.size(); i++) {
if (lists[i] != nullptr) {
pq.push({ lists[i] ->val,lists[i] });
}
}
while (pq.size() > 0) {
for (int i = pq.size(); i > 0; i--) {
t->next = new ListNode(pq.top().first);
ListNode* ttmp = pq.top().second->next;
pq.pop();
if (ttmp)
pq.push({ttmp->val,ttmp});
t = t->next;
}
}
return pre_head->next;
}
};
思路二:采用分治法,每次merge 2个数组,虽然每次merge的时间复杂度是n,但是merge的总次数降到了logk次,所以时间复杂度也是nlogk。
参考代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void mergeToListNode(ListNode* &first, ListNode* &second) {
ListNode* pre_head = new ListNode(-1);
ListNode* tmp = pre_head;
while (first && second) {
tmp->next = new ListNode(first->val < second->val ? first->val : second->val);
if (first->val < second->val)
first = first->next;
else
second = second->next;
tmp = tmp->next;
}
while (first) {
tmp->next = new ListNode(first->val);
tmp = tmp->next;
first = first->next;
}
while (second) {
tmp->next = new ListNode(second->val);
tmp = tmp->next;
second = second->next;
}
first = pre_head->next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.size() == 0)
return nullptr;
int interval = 1, amount = lists.size();
while (interval < amount) {
for (int i = 0; i < (amount - interval); i += interval * 2) {
mergeToListNode(lists[i], lists[i + interval]);
}
interval *= 2;
}
return lists[0];
}
};