题目链接

LeetCode

题目描述

给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 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:

输入: lists = []
输出: []

示例 3:

输入: lists = [[]]
输出: []

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i]升序 排列
  • lists[i].length 的总和不超过 10^4

    解题思路

    方法一:两两链表合并、空间复杂度低

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* mergeKLists(vector<ListNode*>& lists) {
  14. int len = lists.size();
  15. ListNode* ans = nullptr;
  16. for(int i = 0;i<len;i++){
  17. ans = merge2Lists(ans,lists[i]);
  18. }
  19. return ans;
  20. }
  21. ListNode* merge2Lists(ListNode* list1,ListNode* list2){
  22. ListNode* hair = new ListNode();
  23. ListNode* cur = hair;
  24. while(list1&&list2){
  25. if(list1->val<list2->val){
  26. cur->next = list1;
  27. cur = cur->next;
  28. list1 = list1->next;
  29. }else{
  30. cur->next = list2;
  31. cur = cur->next;
  32. list2 = list2->next;
  33. }
  34. }
  35. if(list1){
  36. cur->next = list1;
  37. }
  38. if(list2){
  39. cur->next = list2;
  40. }
  41. return hair->next;
  42. }
  43. };
  • 时间复杂度 O(k^2n):k为链表个数
  • 空间复杂度 O(1)

    方法二:分治合并、方法一的优化,时间复杂度小

    考虑优化方法一,用分治的方法进行合并。

  • 将 k 个链表配对并将同一对中的链表合并;

  • 第一轮合并以后, k 个链表被合并成了 k/2 个链表,平均长度为 2*n/k ,然后是 k/4 个链表,k/8 个链表等等;
  • 重复这一过程,直到我们得到了最终的有序链表。

23. 合并K个升序链表** - 图1

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* mergeKLists(vector<ListNode*>& lists) {
  14. return merge(lists,0,lists.size()-1);
  15. }
  16. ListNode* merge(vector <ListNode*> &lists, int l, int r){
  17. if(l==r)
  18. return lists[l];
  19. if(l>r)
  20. return nullptr;
  21. int mid = l + (r - l)/2;
  22. return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
  23. }
  24. ListNode* mergeTwoLists(ListNode* a,ListNode *b){
  25. if(!a||!b)
  26. return a?a:b;
  27. ListNode* hair = new ListNode();
  28. if(a->val<b->val){
  29. hair->next = a;
  30. a = a->next;
  31. }else{
  32. hair->next = b;
  33. b = b->next;
  34. }
  35. ListNode* cur = hair->next;
  36. while(a&&b){
  37. if(a->val<b->val){
  38. cur->next = a;
  39. a = a->next;
  40. }else{
  41. cur->next = b;
  42. b = b->next;
  43. }
  44. cur = cur->next;
  45. }
  46. cur->next = a==nullptr?b:a;
  47. return hair->next;
  48. }
  49. };
  • 时间复杂度 O(kn*logk):k为链表个数
  • 空间复杂度 O(logk)

    方法三:使用优先队列合并(好)

    这个方法和前两种方法的思路有所不同,我们需要维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val 属性最小的元素合并到答案中。在选取最小元素的时候,我们可以用优先队列来优化这个过程。

    1. class Solution {
    2. public:
    3. struct Status {
    4. int val;
    5. ListNode *ptr;
    6. // 重载<操作符。可以对两个Status使用<操作符进行比较
    7. // C++优先队列默认最大先出,struct的目的就是把最大修改成最小,并无不对。
    8. bool operator < (const Status &rhs) const {
    9. return val > rhs.val;
    10. }
    11. };
    12. priority_queue <Status> q;
    13. // 点号(.):左边必须为实体。
    14. // 箭头(->):左边必须为指针。
    15. ListNode* mergeKLists(vector<ListNode*>& lists) {
    16. // 遍历lists
    17. for (auto node: lists) {
    18. if (node) q.push({node->val, node});
    19. }
    20. ListNode head, *tail = &head;
    21. while (!q.empty()) {
    22. auto f = q.top(); q.pop();
    23. tail->next = f.ptr;
    24. tail = tail->next;
    25. if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});
    26. }
    27. return head.next;
    28. }
    29. };
  • 时间复杂度 O(kn*logk):k为链表个数

  • 空间复杂度 O(k)

    方法五:逐一比较

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode() : val(0), next(nullptr) {}
  7. * ListNode(int x) : val(x), next(nullptr) {}
  8. * ListNode(int x, ListNode *next) : val(x), next(next) {}
  9. * };
  10. */
  11. class Solution {
  12. public:
  13. ListNode* mergeKLists(vector<ListNode*>& lists) {
  14. int len = lists.size();
  15. vector<ListNode*> heads;
  16. for(int i=0;i<len;i++)
  17. heads.push_back(lists[i]);
  18. ListNode* hair = new ListNode(-1);
  19. ListNode* cur = hair;
  20. bool isExit = false;
  21. int minPos = 0;
  22. while(1){
  23. isExit = false;
  24. for(int i=0;i<len;i++){
  25. if(heads[i]!=nullptr){
  26. if(!isExit){
  27. isExit = true;
  28. minPos = i;
  29. }
  30. if(heads[i]->val<heads[minPos]->val){
  31. minPos = i;
  32. }
  33. }
  34. }
  35. if(!isExit){
  36. cur->next = nullptr;
  37. break;
  38. }
  39. cur->next = heads[minPos];
  40. cur = cur->next;
  41. heads[minPos] = heads[minPos]->next;
  42. }
  43. return hair->next;
  44. }
  45. };
  • 时间复杂度 O(kn):k为链表个数,一共n个节点
  • 空间复杂度 O(k)