原题
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example:
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
思路
拍脑门算法
合并k个有序链表,假设每个链表中的元素个数最多为n,那么总共的元素个数为kn个,拍脑门算法可以将每个链表头结点值进行k-1次比较,得到最小的元素放到新的链表里,总共比较次数为kn,时间复杂度为 O ( k 2 n ) O(k^2n) O(k2n)
归并排序
一般出现排序的题目,时间复杂度要尽可能降为 O ( n l o g n ) O(nlogn) O(nlogn)或者 O ( n ) O(n) O(n),而一出现 l o g log log,就要往二叉树上靠,这里可以使用分治法来解决这个问题。
对k个有序链表进行两两排序,然后对排序结果再进行两两排序,重复此步骤,直到最后合成一个链表。
如上图,总共有k个链表,那么上面二叉数的层高为
l
o
g
(
k
)
log(k)
log(k),每层需要比较的元素个数均为
k
n
kn
kn(即所有的元素都要进行一次比较),那么总的时间复杂度为
O
(
k
n
l
o
g
(
k
)
)
O(knlog(k))
O(knlog(k))
代码
class Solution {
public:
//假设lists中的(l, m), (m+1, r)区间已经完成合并,并且合并的链表头结点在lists[l],lists[m+1]
//然后合并lists[l],lists[m+1]两个链表,并将头结点赋予lists[l])(即最左边的索引)
void merge(vector<ListNode*> &lists, int l, int m, int r) {
ListNode *p = lists[l], *q = lists[m+1];
ListNode *new_list = NULL, *head = NULL;
//判断两个链表是否为空
if (q == NULL) return ;
if (p == NULL) {
lists[l] = q;
return ;
}
new_list = new ListNode(-1);
head = new_list;
while (p != NULL && q != NULL)
{
if (q->val < p->val)
{
new_list->next = new ListNode(q->val);
q = q->next;
}
else
{
new_list->next = new ListNode(p->val);
p = p->next;
}
new_list = new_list->next;
}
if(p == NULL)
new_list->next = q;
if(q == NULL)
new_list->next = p;
lists[l] = head->next;
}
//分治法
//将lists分为(l, m), (m+1, r)两个部分,分别进行合并,并将合并好的链表头结点赋予lists[l], lists[m+1](即最左边的索引)
//合并lists(l), lists[m+1]
void divide_conquer(vector<ListNode*> &lists, int l, int r) {
if (l < r) {
int m = (l+r)/2;
divide_conquer(lists, l, m);
divide_conquer(lists, m+1, r);
merge(lists, l, m, r);
}
}
//返回最左边索引的头结点
ListNode* mergeKLists(vector<ListNode*>& lists)
{
if (lists.size() == 0)
return NULL;
divide_conquer(lists, 0, lists.size() - 1);
return lists[0];
}
};