题目描述
给定一个链表数组,每个链表都已经按升序排列。
请将所有链表合并到一个升序链表中,返回合并后的链表。
示例 1:
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:
**示例 2:**
示例 3:
输入:lists = [[]]
输出:[]
解题方法
归并排序法
1、解题思路
和上述排序链表同样的思路,将K个链表进行分治,分治的最小单元是只有一个链表,然后两两合并已排好的链表。
2、代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode* node = nullptr;
// 链表数组为空
if (lists.size() == 0) {
return node;
}
// 链表数组中只有一个链表并且该链表也为空
else if (lists.size() == 1 && lists[0] == nullptr) {
return node;
} else {
return merge(lists);
}
}
ListNode* merge(vector<ListNode*>& lists) {
// 当数组中只有一个链表时,不需要分治也不需要排序,直接返回该链表的头节点即可
if (lists.size() == 1) {
return lists[0];
}
// 使用对应的下标寻找中间链表
int mid = lists.size() / 2;
vector<ListNode*> left, right;
// 进行分割
left.assign(lists.begin(), lists.begin() + mid);
right.assign(lists.begin() + mid, lists.end());
// 处理子问题
ListNode* list1 = merge(left);
ListNode* list2 = merge(right);
// 合并两个链表
return mergeTwoList(list1, list2);
}
// 同上述排序链表一样的合并代码
ListNode* mergeTwoList(ListNode* node1, ListNode* node2) {
ListNode *node, *p, *q, *t;
node = new ListNode();
node->next = nullptr;
t = node;
p = node1;
q = node2;
while (p != nullptr && q != nullptr) {
if (p->val <= q->val) {
t->next = p;
t = t->next;
p = p->next;
} else {
t->next = q;
t = t->next;
q = q->next;
}
}
if (p) {
t->next = p;
} else if (q) {
t->next = q;
} else {
t->next = nullptr;
}
return node->next;
}
};
3、复杂度分析
(1)时间复杂度:merge函数的递归深度为logn,查找中间链表的时间复杂度为O(1),mergeTwoList函数的时间复杂度为O(m+n),则merge每一层的时间复杂度为O(n),总的时间复杂度T(n)=O(nlogn)。
(2)空间复杂度:使用了两个辅助vector数组,则空间复杂度S(n)=O(n)。