题目:
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 合并K个已排序的链表,并将排序结果返回,分析和描述复杂性。
一看到这道题,由于K个链表已经是排好序的,最简单的做法就是每次找出K个链表里最小的那个元素,放入新的链表中。每次选择一个元素的复杂度是O(k),操作的复杂度是O(n),所以总共的时间复杂度是O(kn),空间复杂度是O(n)。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int n = lists.size();
if (n == 0)
return NULL;
for (int i = 0; i<lists.size(); i++)
{
if (lists[i] == NULL)
{
lists.erase(lists.begin() + i);
i--;
}
}//预处理清楚为空的链表
if (lists.size() == 0)
return NULL;//特殊情况判断
ListNode head(0);
ListNode *p = &head;
while (lists.size())
{
int Min = lists[0]->val;
int index = 0;
for (int i = 0; i < lists.size(); ++i)
{
if (lists[i] != NULL && lists[i]->val < Min)
{
index = i;
Min = lists[i]->val;
}
}//找出K个链表中最小的元素
p->next = lists[index];//将找出的元素放到新的链表
p = p->next;
lists[index] = lists[index]->next;
if (lists[index] == NULL)
lists.erase(lists.begin() + index);//如果某个链表为空,及时清除
}
return head.next;
}
};
上面的做法固然简单,但是复杂度方面仍然有改善的空间。改善的思路就是这周老师上课讲的分治思想,将合并K个链表的任务分成合并更小的链表的任务,比如K/2,又将合并K/2个链表的任务分成合并K/4个链表,一直划分下去直到任务变成合并1个或者2个链表。算法的时间复杂度为O(nklogk),空间复杂度是O(n)。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int n = lists.size();
if(n == 0)
return NULL;
while(n > 1)
{
for(int i = 0; i < n/2; ++i)
lists[i] = merge(lists[i], lists[i+(n+1)/2]);//分治归并排序
n = (n+1)/2;
}
return lists[0];
}
ListNode* merge(ListNode* node1, ListNode* node2)
{
ListNode *head = NULL;
if(node1 == NULL)
return node2;//特殊情况判断
if(node2 == NULL)
return node1;//特殊情况判断
if(node1->val <= node2->val)//特殊情况判断
{
head = node1;
node1 = node1->next;
}
else//特殊情况判断
{
head = node2;
node2 = node2->next;
}
ListNode *p = head;
while(node1 && node2)
{
if(node1->val <= node2->val)//找到两个链表最小的元素,放入新的链表
{
p->next = node1;
node1 = node1->next;
}
else
{
p->next = node2;
node2 = node2->next;
}
p = p->next;
}
if(node1)//假如其中一条链表没有到尾巴,剩余的元素全部放入新的链表
p->next = node1;
else if(node2)
p->next = node2;
return head;
}
};