Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
函数原型如下:
ListNode *mergeKLists(vector<ListNode *> &lists)
给定一个向量(vector),存储的是每个链表的头指针。要求是把这k个有序链表合并成一个有序的链表输出。
我们可以采用分治法进行处理,分治法在算法结构上要求是能递归的。算法一次或者多次调用自身以解决紧密相关的子问题。
分支法就是将原问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题即可。然后再合并这些子问题的解合并出原问题的解。
分治模式在每层中递归时都有三个步骤,
分解:将原问题分解为子问题。分解n个待排序的链表成各有n/2个链表的子问题。
解决:解决子问题,递归的求解子问题,当然若子问题足够小(只有两个链表)就直接求解。使用递归,一次处理这两个子链表组。
合并:合并子问题的解为原问题的解。将两个链表合为一个链表,循环往复。
代码如下:
<span style="font-size:18px;">/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *mergeTwoList(ListNode *l1,ListNode *l2)
{//合并两个有序的链表,是在原空间上进行的指针操作,复杂度为O(n)
ListNode *helper = new ListNode(0);
ListNode *pre = helper;
helper->next = l1;//让要返回的链表直接连接到l1上,如果l1->val较小,则插入到l1前面
while(l1!=NULL && l2!=NULL)
{
if(l1->val>l2->val)
{
ListNode * p = l2;
l2 = l2->next;
p->next = pre->next;
pre->next = p;
}
else
l1 = l1->next;
pre = pre->next;
}
if(l2!=NULL)//把最后剩下的l2全部链接到l1后面
pre->next = l2;
return helper->next;
}
ListNode *helper(vector<ListNode*> lists,int l,int h)
{
if(l<h)
{
int m = (l+h)/2;
return mergeTwoList(helper(lists,l,m),helper(lists,m+1,h));//合并子问题的解
}
return lists[l];
}
ListNode *mergeKLists(vector<ListNode *> &lists) {
if(lists.size() == 0)
return NULL;
return helper(lists,0,lists.size()-1);//求解子问题
}
};</span>
下面给出使用堆排序方式的合并方法。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
struct cmp {
bool operator() (ListNode *a, ListNode *b) {
return a->val > b->val;
}
};
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
priority_queue<ListNode *, vector<ListNode *>, cmp> queue;
for (int i = 0; i < lists.size(); i++) {
if (lists[i] != NULL) {
queue.push(lists[i]);
}
}
ListNode *head = NULL, *prev = NULL, *temp;
while (!queue.empty()) {
temp = queue.top();
queue.pop();
if (prev == NULL) {
head = temp;
}
else {
prev->next = temp;
}
prev = temp;
if (temp->next != NULL) {
queue.push(temp->next);
}
}
return head;
}
};