合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
/**
* 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) {
//代码实现
}
};
此题解法是在合并两个有序链表的基础上进行扩展的,请先查看我合并两个有序链表的算法博客。这道题就是找到一个非空的链表,然后与一个非空的链表合并,并立即将中间结果更新为一条链表去合并下一条非空链表。
ListNode* mergeKLists(vector<ListNode*>& lists) {
int length = lists.size();
if (length == 0) {
return NULL;
}
if (length == 1) {
return lists[0];
}
ListNode *listOne = NULL, *listTwo;
int begin = 0;
//寻找第一个非空的头结点
while (begin < length && lists[begin] == 0) {
++begin;
}
//如果所有的都是空链表
if (begin >= length) {
return NULL;
}
//初始化为第一个非空的链表
listOne = lists[begin];
//不断的将第i个链表与listOne合并,合并后立即更新listOne,然后合并i+1
for (int i = begin + 1; i < length; ++i) {
listTwo = lists[i];
//判断第i个是否为空
if (listTwo == NULL) {
continue;
}
//非空就与listOne合并
ListNode *resultList = NULL;//合并后的表头
ListNode *ptr = NULL;//合并后的表尾
//首先放入一个节点到结果中
if (listOne->val < listTwo->val) {
resultList = ptr = listOne;
listOne = listOne->next;
}
else {
resultList = ptr = listTwo;
listTwo = listTwo->next;
}
//只有当两个链表都剩余节点时,才可进行比较
while (listOne != NULL && listTwo != NULL) {
if (listOne->val < listTwo->val) {
//将表头添加到结果链表的表尾
ptr->next = listOne;
ptr = ptr->next;
listOne = listOne->next;
}
else {
//将表头添加到结果链表的表尾
ptr->next = listTwo;
ptr = ptr->next;
listTwo = listTwo->next;
}
}
//因为是链表,其本身就是连接好的,无需进行一个一个的移动
if (listOne != NULL) {
ptr->next = listOne;
}
if (listTwo != NULL) {
ptr->next = listTwo;
}
//将listOne更新为合并之后的结果
listOne = resultList;
}
return listOne;
}
不过时间复杂度有点大。。。
经过翻阅评论区,发现有种比较屌的思路,就是利用并归算法的思路,逐个的将两两相邻的链表合并,最后合成最终的链表。
//struct ListNode {
// int val;
// ListNode *next;
// ListNode(int x) : val(x), next(NULL) {}
//};
ListNode* mergeKLists(vector<ListNode*>& lists) {
int length = lists.size();
if (length == 0) {
return NULL;
}
if (length == 1) {
return lists[0];
}
vector<ListNode*> notNullLists;//将原容器中的非空链表挑出
int count = 0;//非空链表数
for (vector<ListNode*>::iterator it = lists.begin(); it != lists.end(); ++it) {
if (*it != NULL) {
notNullLists.push_back(*it);
++count;
}
}
if (count == 0) {
//如果无非空链表
return NULL;
}
if (count == 1) {
//如果只有一条非空链表
return notNullLists[0];
}
//将非空链表进行合并,从下标0 到 count-1
ListNode *resultList = mergeKLists(notNullLists, 0, count - 1);
return resultList;
}
//递归定义从lists下标begin到end的链表合并
ListNode *mergeKLists(vector<ListNode*>& lists, int begin, int end) {
if (end == begin) {
return lists[end];
}
else if (end == begin + 1) {
return mergeTwoLists(lists[begin], lists[end]);
}
else {
int mid = (end + begin) / 2;
ListNode *leftList = mergeKLists(lists, begin, mid);//合并左半部分
ListNode *rightList = mergeKLists(lists, mid + 1, end);//合并右半部分
return mergeTwoLists(leftList, rightList);//左右合并
}
}
//合并两条链表的算法实现
ListNode* mergeTwoLists(ListNode* listOne, ListNode* listTwo) {
if (listOne == NULL) {
return listTwo;
}
if (listTwo == NULL) {
return listOne;
}
ListNode *resultList = NULL;//合并后的表头
ListNode *ptr = NULL;//合并后的表尾
//首先放入一个节点到结果中
if (listOne->val < listTwo->val) {
resultList = ptr = listOne;
listOne = listOne->next;
}
else {
resultList = ptr = listTwo;
listTwo = listTwo->next;
}
//只有当两个链表都剩余节点时,才可进行比较
while (listOne != NULL && listTwo != NULL) {
if (listOne->val < listTwo->val) {
//将表头添加到结果链表的表尾
ptr->next = listOne;
ptr = ptr->next;
listOne = listOne->next;
}
else {
//将表头添加到结果链表的表尾
ptr->next = listTwo;
ptr = ptr->next;
listTwo = listTwo->next;
}
}
//因为是链表,其本身就是连接好的,无需进行一个一个的移动
if (listOne != NULL) {
ptr->next = listOne;
}
if (listTwo != NULL) {
ptr->next = listTwo;
}
return resultList;
}
如果不怎么理解该算法,请先参考我合并两条有序链表的算法实现。至于并归思想,后期如果有时间会出并归排序算法,也可自行百度。