【LeetCode】23. 合并K个排序链表
题目
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
思路一:顺序合并
基于合并两个链表,取第一个链表与第二个链表合并,然后将合并的链表再与第三个链表合并,依次类型。
代码
时间复杂度:假设每个链表的最长长度是 n,渐进时间复杂度为 O(k^2 * n)
。
空间复杂度:没有用到与 k 和 n 规模相关的辅助空间,故渐进空间复杂度为 O(1)。
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
if (lists.empty()) return nullptr;
int n = lists.size();
ListNode *res = lists[0];
for (int i = 1; i < n; ++i) {
res = mergeTwoLists(res, lists[i]);
}
return res;
}
ListNode* merge2(ListNode *l1, ListNode *l2) {
ListNode *root = new ListNode(0), *pre = root;
while (l1 && l2) {
if (l1->val <= l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
pre->next = l1 ? l1 : l2;
return root->next;
}
};
思路二:分治合并放入队列
基于merge思想,将k个链表放入队列,取出两个进行合并,合并后在放入队尾,直到只有队列中只有一个元素。
注意:vector转队列需要先转双端队列。
代码
击败99.05%
时间复杂度:考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn * logk)。
空间复杂度:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int size = lists.size();
if (size == 0) {
return nullptr;
}
if (size == 1) {
return lists[0];
}
queue<ListNode*> waiting(deque<ListNode*>(lists.begin(), lists.end())); //将vector转为队列
//如果队列元素大于1,则取出两个进行合并,合并后的链表继续添加到链表尾部
while (waiting.size() > 1) {
ListNode *l1 = waiting.front();
waiting.pop();
ListNode *l2 = waiting.front();
waiting.pop();
ListNode *p = merge2(l1, l2);//可以取消生成变量
waiting.push(p);
}
return waiting.front();
}
ListNode* merge2(ListNode *l1, ListNode *l2) {
ListNode *root = new ListNode(0), *pre = root;
while (l1 && l2) {
if (l1->val <= l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
pre->next = l1 ? l1 : l2;
return root->next;
}
};
化简代码
减少生成中间变量。
击败100%
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int size = lists.size();
if (size == 0) {
return nullptr;
}
if (size == 1) {
return lists[0];
}
queue<ListNode*> waiting(deque<ListNode*>(lists.begin(), lists.end())); //将vector转为队列
//如果队列元素大于1,则取出两个进行合并,合并后的链表继续添加到链表尾部
while (waiting.size() > 1) {
ListNode *l1 = waiting.front();
waiting.pop();
ListNode *l2 = waiting.front();
waiting.pop();
waiting.push(merge2(l1, l2));
}
return waiting.front();
}
ListNode* merge2(ListNode *l1, ListNode *l2) {
ListNode *root = new ListNode(0), *pre = root;
while (l1 && l2) {
if (l1->val <= l2->val) {
pre->next = l1;
l1 = l1->next;
} else {
pre->next = l2;
l2 = l2->next;
}
pre = pre->next;
}
pre->next = l1 ? l1 : l2;
return root->next;
}
};