合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度
样例
归并方法(两两合并)大神解法,好好体会
给出3个排序链表[2->4->null,null,-1->null],返回 -1->2->4->null
思想:与合并两个排序链表类似,只不过这个是多个链表
假设有两个排序链表 1->2->3->null, 2->4->null,
程序具体流程如下
我们采用分治的方法来解决这个问题,其有K个链表,不断将其划分(partition),再将其归并(merge)。
划分的部分并不难,将其不断分成两部分,但是需要注意的是可能出现start和end相等的情况,这时候就直接return lists[start]就可以了。
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*> &lists) {
return partition(lists, 0, lists.size() - 1);
}
//写递归函数时,要先确定递归截止的条件,再想如何递归
ListNode* partition(vector<ListNode*>& lists, int start, int end) {
if(start == end) {
return lists[start];//递归截止条件
}
int mid = (start + end) / 2;
ListNode* l1 = partition(lists, start, mid);
ListNode* l2 = partition(lists, mid + 1, end);
mergeTwoLists(l1, l2);
}
两个排序链表的合并
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l2 == NULL) return l1;
if(l1 == NULL) return l2;
if(l1->val > l2->val) {
ListNode* temp = l2;
temp->next = mergeTwoLists(l1, l2->next);
return temp;
} else {
ListNode* temp = l1;
temp->next = mergeTwoLists(l1->next, l2);
return temp;
}
}
};
4、利用堆
我们再来看另一种解法,这种解法利用了最小堆这种数据结构,我们首先把k个链表的首元素都加入最小堆中,它们会自动排好序。然后我们每次取出最小的那个元素加入我们最终结果的链表中,然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作,以此类推,直到堆中没有元素了,此时k个链表也合并为了一个链表,返回首节点即可,代码如下:
struct cmp {
bool operator () (ListNode *a, ListNode *b) {
return a->val > b->val;
}
};
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
priority_queue<ListNode*, vector<ListNode*>, cmp> q;
for (int i = 0; i < lists.size(); ++i) {
if (lists[i]) q.push(lists[i]);
}
ListNode *head = NULL, *pre = NULL, *tmp = NULL;
while (!q.empty()) {
tmp = q.top();
q.pop();
if (!pre) head = tmp;
else pre->next = tmp;
pre = tmp;
if (tmp->next) q.push(tmp->next);
}
return head;
}
};