方法一:归并排序
利用双指针和分治(递归)的思想来求解
可以将问题分解为两个有序链表的合并的小问题,并且不断地向上递归,最终就可以将K个链表按顺序合并到一起。
时间复杂度:o(nlogk);递归有logk层,n为所有链表的总结点数,复杂度为o(nlogk)。
空间复杂度:o(logk),需要logk的递归栈。
class Solution { public: //合并两个有序链表 ListNode* merge(ListNode* phead1, ListNode* phead2) { if (phead1 == nullptr) return phead2; if (phead2 == nullptr) return phead1; ListNode* res = new ListNode(0); ListNode* cur = res; while (phead1 && phead2) { if (phead1->val < phead2->val) { cur->next = phead1; phead1 = phead1->next; } else { cur->next = phead2; phead2 = phead2->next; } cur = cur->next; } if (phead1) cur->next = phead1; if (phead2) cur->next = phead2; return res->next; } ListNode* divideLists(vector<ListNode*>& lists, int left, int right) { //特殊情况处理 if (left > right) return nullptr; if (left == right) return lists[left]; int mid = (left + right) / 2; //拆分为子问题,并且向上递归,最终的合并所有的链表 return merge(divideLists(lists, left, mid), divideLists(lists, mid + 1, right)); } ListNode* mergeKLists(vector<ListNode*>& lists) { return divideLists(lists, 0, lists.size() - 1); } };
方法二:辅助空间排序
1、创建数组,将K个链表存储到数组中;
2、对数组中的元素进行排序(快排);
3、将数组转换为链表即得到按顺序合并后的链表。
时间复杂度:o(nlogn)。遍历需要的时间为o(n);快排需要的时间为o(nlogn)。
空间复杂度:o(n)。需要辅助数组存储所有链表的结点的值。
class Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { if (lists.size() == 0) return nullptr; if (lists.size() == 1) return lists[0]; vector<int> vect; for (int i = 0; i < lists.size(); i++) { ListNode* temp = lists[i]; while (temp) { vect.push_back(temp->val); temp = temp->next; } } sort(vect.begin(), vect.end()); ListNode* res = new ListNode(0); ListNode* phead = res; for (int i = 0; i < vect.size(); i++) { phead->next = new ListNode(vect[i]); phead = phead->next; } phead->next = nullptr; return res->next; } };
拓展思路
方法三:小顶堆